Example #1
0
    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()
Example #2
0
    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()
Example #3
0
    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()
Example #4
0
    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 set_db_connection(self, db, test_conn_result=None):
        """
        Set the DB connection info this class will use to build the GUI.

        :param db: DBConnector object
        :param test_conn_result: Can be True or False if test_connection was called, or None if we should call it.
        :return:
        """
        self._db = db
        self._test_conn_result = test_conn_result if test_conn_result is not None else db.test_connection(
        )[0]
        db_factory = ConfigDBsSupported().get_db_factory(db.engine)
        self._db_engine_actions = db_factory.get_db_engine_actions()
        self._engine_name = db_factory.get_name()
    def __init__(self, db, ladm_data):
        QObject.__init__(self)

        self._db = db
        self._ladm_data = ladm_data

        self.logger = Logger()
        self.app = AppInterface()
        self.clipboard = QApplication.clipboard()
        self._layers = dict()
        self._ladm_queries = ConfigDBsSupported().get_db_factory(
            self._db.engine).get_ladm_queries()

        self._restart_dict_of_layers()
        self._add_layers()

        # To cache informal parcels,
        self._informal_parcels_info = tuple(
        )  # ([parcel_t_id: parcel_number], [,], [,], ...)
        self._informal_index = -1
        self._informal_parcels_len = 0  # To avoid calculating this each time
Example #7
0
    def set_db_connection(self, db, test_conn_result=None):
        """
        Set the DB connection info this class will use to build the GUI.

        :param db: DBConnector object
        :param test_conn_result: Can be True or False if test_connection was called, or None if we should call it.
        :return:
        """
        self._db = db

        if test_conn_result is not None:
            self._test_conn_result = test_conn_result
        else:
            self._test_conn_result, code, msg = db.test_connection()
            if not self._test_conn_result:
                self.logger.warning(
                    __name__,
                    "Test connection is False! Details: {}".format(msg))

        db_factory = ConfigDBsSupported().get_db_factory(db.engine)
        self._db_engine_actions = db_factory.get_db_engine_actions()
        self._engine_name = db_factory.get_name()
Example #8
0
 def _get_ladm_queries(self, engine):
     return ConfigDBsSupported().get_db_factory(engine).get_ladm_queries()
Example #9
0
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)
    def __init__(self, conn_manager=None, context=None, parent=None):
        QDialog.__init__(self, parent)
        self.setupUi(self)
        self.parent = parent
        self.logger = Logger()
        self.conn_manager = conn_manager
        self.app = AppInterface()

        self.sbx_tolerance.setMaximum(TOLERANCE_MAX_VALUE)
        self._valid_document_repository = False  # Needs to be True if users want to enable doc repo (using test button)

        context = context if context else SettingsContext()

        self.db_source = context.db_source  # default db source is COLLECTED_DB_SOURCE
        self._required_models = context.required_models
        self._tab_pages_list = context.tab_pages_list
        self._blocking_mode = context.blocking_mode  # Whether the dialog can only be accepted on valid DB connections or not
        self._action_type = context.action_type  # By default "config"
        self.setWindowTitle(context.title)

        self._db = None
        self.init_db_engine = None
        self.dbs_supported = ConfigDBsSupported()
        self._open_dlg_import_schema = False  # After accepting, if non-valid DB is configured, we can go to import schema

        self.online_models_radio_button.setEnabled(
            False)  # This option is disabled until we have online models back!
        self.online_models_radio_button.setChecked(True)
        self.online_models_radio_button.toggled.connect(
            self.model_provider_toggle)
        self.custom_model_directories_line_edit.setText("")
        self.custom_models_dir_button.clicked.connect(
            self.show_custom_model_dir)
        self.custom_model_directories_line_edit.setVisible(False)
        self.custom_models_dir_button.setVisible(False)

        # Set connections
        self.buttonBox.accepted.disconnect()
        self.buttonBox.accepted.connect(self.accepted)
        self.buttonBox.helpRequested.connect(self.show_help)
        self.finished.connect(self.finished_slot)
        self.btn_test_connection.clicked.connect(self.test_connection)
        self.btn_test_ladm_col_structure.clicked.connect(
            self.test_ladm_col_structure)

        self.btn_test_service.clicked.connect(self.test_service)
        self.btn_test_service_transitional_system.clicked.connect(
            self.test_service_transitional_system)
        self.txt_service_endpoint.textEdited.connect(
            self.source_service_endpoint_changed)  # For manual changes only

        self.btn_default_value_sources.clicked.connect(
            self.set_default_value_source_service)
        self.btn_default_value_transitional_system.clicked.connect(
            self.set_default_value_transitional_system_service)

        self.chk_use_roads.toggled.connect(self.update_images_state)

        self.bar = QgsMessageBar()
        self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.layout().addWidget(self.bar, 0, 0, Qt.AlignTop)

        self.cbo_db_engine.clear()

        self._lst_db = self.dbs_supported.get_db_factories()
        self._lst_panel = dict()

        for key, value in self._lst_db.items():
            self.cbo_db_engine.addItem(value.get_name(), key)
            self._lst_panel[key] = value.get_config_panel(self)
            self._lst_panel[key].notify_message_requested.connect(
                self.show_message)
            self.db_layout.addWidget(self._lst_panel[key])

        self.db_engine_changed()

        # Trigger some default behaviours
        self.restore_db_source_settings(
        )  # restore settings with default db source
        self.restore_settings()

        self.roles = RoleRegistry()
        self.load_roles()

        self.cbo_db_engine.currentIndexChanged.connect(self.db_engine_changed)
        self.rejected.connect(self.close_dialog)

        self._update_tabs()

        if context.tip:
            self.show_tip(context.tip)
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)
Example #12
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
Example #13
0
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
    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()
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 LADMQueryController(QObject):

    close_view_requested = pyqtSignal()
    zoom_to_features_requested = pyqtSignal(QgsVectorLayer, list,
                                            dict)  # layer, ids, t_ids

    def __init__(self, db, ladm_data):
        QObject.__init__(self)

        self._db = db
        self._ladm_data = ladm_data

        self.logger = Logger()
        self.app = AppInterface()
        self.clipboard = QApplication.clipboard()
        self._layers = dict()
        self._ladm_queries = ConfigDBsSupported().get_db_factory(
            self._db.engine).get_ladm_queries()

        self._restart_dict_of_layers()
        self._add_layers()

        # To cache informal parcels,
        self._informal_parcels_info = tuple(
        )  # ([parcel_t_id: parcel_number], [,], [,], ...)
        self._informal_index = -1
        self._informal_parcels_len = 0  # To avoid calculating this each time

    def _add_layers(self):
        self.app.core.get_layers(self._db, self._layers, load=True)
        if not self._layers:
            self._restart_dict_of_layers()  # Let it ready for the next call
            return None

        # Layer was found, listen to its removal so that we can deactivate the custom tool when that occurs
        self.disconnect_plot_layer()
        self._layers[self._db.names.LC_PLOT_T].willBeDeleted.connect(
            self._plot_layer_removed)

        # Layer was found, listen to its removal so that we can update the variable properly
        self.disconnect_parcel_layer()
        self._layers[self._db.names.LC_PARCEL_T].willBeDeleted.connect(
            self._parcel_layer_removed)

        # Layer was found, listen to its removal so that we can update the variable properly
        try:
            self._layers[
                self._db.names.COL_UE_BAUNIT_T].willBeDeleted.disconnect(
                    self._uebaunit_table_removed)
        except:
            pass
        self._layers[self._db.names.COL_UE_BAUNIT_T].willBeDeleted.connect(
            self._uebaunit_table_removed)

    def _restart_dict_of_layers(self):
        self._layers = {
            self._db.names.LC_PLOT_T: None,
            self._db.names.LC_PARCEL_T: None,
            self._db.names.COL_UE_BAUNIT_T: None
        }

    def plot_layer(self):
        if self._layers[self._db.names.LC_PLOT_T] is None:
            self._add_layers()
        return self._layers[self._db.names.LC_PLOT_T]

    def parcel_layer(self):
        if self._layers[self._db.names.LC_PARCEL_T] is None:
            self._add_layers()
        return self._layers[self._db.names.LC_PARCEL_T]

    def uebaunit_table(self):
        if self._layers[self._db.names.COL_UE_BAUNIT_T] is None:
            self._add_layers()
        return self._layers[self._db.names.COL_UE_BAUNIT_T]

    def _plot_layer_removed(self):
        # The required layer was removed
        self.close_view_requested.emit()
        self._layers[self._db.names.LC_PLOT_T] = None

    def _parcel_layer_removed(self):
        self._layers[self._db.names.LC_PARCEL_T] = None

    def _uebaunit_table_removed(self):
        self._layers[self._db.names.COL_UE_BAUNIT_T] = None

    def disconnect_plot_layer(self):
        try:
            self._layers[self._db.names.LC_PLOT_T].willBeDeleted.disconnect(
                self._plot_layer_removed)
        except:
            pass

    def disconnect_parcel_layer(self):
        try:
            self._layers[self._db.names.LC_PARCEL_T].willBeDeleted.disconnect(
                self._parcel_layer_removed)
        except:
            pass

    def parcel_layer_name(self):
        return self._db.names.LC_PARCEL_T

    def t_id_name(self):
        return self._db.names.T_ID_F

    def parcel_number_name(self):
        return self._db.names.LC_PARCEL_T_PARCEL_NUMBER_F

    def previous_parcel_number_name(self):
        return self._db.names.LC_PARCEL_T_PREVIOUS_PARCEL_NUMBER_F

    def fmi_name(self):
        return self._db.names.LC_PARCEL_T_FMI_F

    def create_model(self, records):
        return TreeModel(self._db.names, data=records)

    def update_db_connection(self, db, ladm_col_db, db_source):
        self.close_view_requested.emit()

    def copy_value(self, value):
        self.clipboard.setText(str(value))

    def open_url(self, url):
        webbrowser.open(url)

    def zoom_to_feature(self, layer, t_id):
        self.zoom_to_features_requested.emit(layer, list(),
                                             {self._db.names.T_ID_F: [t_id]})

    def zoom_to_plots(self, plot_ids):
        self.zoom_to_features_requested.emit(self.plot_layer(), plot_ids,
                                             dict())

    def zoom_to_resulting_plots(self, records):
        # Zoom to plots retrieved from a search
        plot_t_ids = self._get_plot_t_ids_from_basic_info(records)
        if plot_t_ids:
            features = self._ladm_data.get_features_from_t_ids(
                self._layers[self._db.names.LC_PLOT_T], self._db.names.T_ID_F,
                plot_t_ids, True, True)
            plot_ids = [feature.id() for feature in features]
            self.zoom_to_features_requested.emit(self.plot_layer(), plot_ids,
                                                 dict())
            self.plot_layer().selectByIds(plot_ids)

    def _get_plot_t_ids_from_basic_info(self, records):
        res = []
        if records:
            if self._db.names.LC_PLOT_T in records:
                for element in records[self._db.names.LC_PLOT_T]:
                    res.append(element['id'])

        return res

    def open_feature_form(self, layer, t_id):
        # Note that it is important to fetch all feature attributes from the next call
        features = self._ladm_data.get_features_from_t_ids(
            layer, self._db.names.T_ID_F, [t_id], no_geometry=True)
        if features:
            self.app.gui.open_feature_form(layer, features[0])
        else:
            self.logger.warning(
                __name__,
                "No feature found in layer '{}' with t_id '{}'!!!".format(
                    layer.name(), t_id))

    def download_image(self, url):
        res = False
        img = None
        msg = {'text': '', 'level': Qgis.Warning}
        if url:
            self.logger.info(__name__, "Downloading file from {}".format(url))
            msg_status_bar = "Downloading image from document repository (this might take a while)..."
            with ProcessWithStatus(msg_status_bar):
                if is_connected(TEST_SERVER):

                    nam = QNetworkAccessManager()
                    request = QNetworkRequest(QUrl(url))
                    reply = nam.get(request)

                    loop = QEventLoop()
                    reply.finished.connect(loop.quit)
                    loop.exec_()

                    status = reply.attribute(
                        QNetworkRequest.HttpStatusCodeAttribute)
                    if status == 200:
                        res = True
                        img = reply.readAll()
                    else:
                        res = False
                        msg['text'] = QCoreApplication.translate(
                            "SettingsDialog",
                            "There was a problem connecting to the server. The server might be down or the service cannot be reached at the given URL."
                        )
                else:
                    res = False
                    msg['text'] = QCoreApplication.translate(
                        "SettingsDialog",
                        "There was a problem connecting to Internet.")

        else:
            res = False
            msg['text'] = QCoreApplication.translate("SettingsDialog",
                                                     "Not valid URL")

        if not res:
            self.logger.log_message(__name__, msg['text'], msg['level'])

        return res, img

    def get_plots_related_to_parcel(self, parcel_t_id):
        return self._ladm_data.get_plots_related_to_parcels(
            self._db, [parcel_t_id], None, self.plot_layer(),
            self.uebaunit_table())

    def get_layer(self, table_name):
        return self.app.core.get_layer(self._db, table_name, True)

    def search_data_basic_info(self, **kwargs):
        return self._ladm_queries.get_igac_basic_info(self._db, **kwargs)

    def search_data_legal_info(self, **kwargs):
        return self._ladm_queries.get_igac_legal_info(self._db, **kwargs)

    def search_data_physical_info(self, **kwargs):
        return self._ladm_queries.get_igac_physical_info(self._db, **kwargs)

    def search_data_economic_info(self, **kwargs):
        return self._ladm_queries.get_igac_economic_info(self._db, **kwargs)

    def query_informal_parcels(self):
        """
        :return: Triple --> parcel_number, current, total
        """
        # We always go to the DB to get informality info
        parcel_layer = self.app.core.get_layer(self._db,
                                               self._db.names.LC_PARCEL_T,
                                               True)
        informal_parcel_t_ids = self._ladm_data.get_informal_parcel_tids(
            self._db, parcel_layer)

        # Overwrite cache
        self._informal_parcels_info = tuple()
        self._informal_index = -1
        self._informal_parcels_len = 0

        if informal_parcel_t_ids:
            # Get parcel info ordered by parcel number
            parcels = self._ladm_data.get_features_from_t_ids(
                self.parcel_layer(),
                self._db.names.T_ID_F,
                informal_parcel_t_ids,
                no_attributes=False,
                no_geometry=False,
                only_attributes=[self._db.names.LC_PARCEL_T_PARCEL_NUMBER_F],
                order_by=self._db.names.LC_PARCEL_T_PARCEL_NUMBER_F)

            # Create a tuple of lists ([t_id: parcel_number], ...)
            self._informal_parcels_info = tuple([
                p[self._db.names.T_ID_F], p[
                    self._db.names.LC_PARCEL_T_PARCEL_NUMBER_F]
            ] for p in parcels)
            self._informal_parcels_len = len(self._informal_parcels_info)

        return self.get_next_informal_parcel()

    def get_next_informal_parcel(self):
        return self._traverse_informal_parcel_info()

    def get_previous_informal_parcel(self):
        return self._traverse_informal_parcel_info(False)

    def _traverse_informal_parcel_info(self, next=True):
        """
        Get a triple corresponding to an informal parcel number, the current index and the total of parcels.
        Note that if we get to the end and ask for the next parcel, we start over again. Similarly. if we are in the 1st
        parcel and ask for the previous one, then we get the latest one.

        :param next: Whether we need the next parcel's info or the previous one.
        :return: Triple --> parcel_number, current_idx, total_parcels (the current_idx returned is for display purposes)
        """
        if not self._informal_parcels_len:
            return '', 0, 0

        index = self._informal_index  # Get current index

        if next:  # Now set the current index
            self._informal_index = index + 1 if index + 1 < self._informal_parcels_len else 0
        else:  # Previous
            self._informal_index = index - 1 if index >= 1 else self._informal_parcels_len - 1

        return self._informal_parcels_info[self._informal_index][
            1], self._informal_index + 1, self._informal_parcels_len
    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)
Example #18
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
Example #19
0
 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()
Example #20
0
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 SettingsDialog(QDialog, DIALOG_UI):
    """
    Customizable dialog to configure LADM-COL Assistant.

    It can be created passing a SettingsContext with specific params
    or it can be instantiated and then set params one by one.
    """
    db_connection_changed = pyqtSignal(DBConnector, bool,
                                       str)  # dbconn, ladm_col_db, source
    open_dlg_import_schema = pyqtSignal(
        Context)  # Context for the import schema dialog

    def __init__(self, conn_manager=None, context=None, parent=None):
        QDialog.__init__(self, parent)
        self.setupUi(self)
        self.parent = parent
        self.logger = Logger()
        self.conn_manager = conn_manager
        self.app = AppInterface()

        self.sbx_tolerance.setMaximum(TOLERANCE_MAX_VALUE)
        self._valid_document_repository = False  # Needs to be True if users want to enable doc repo (using test button)

        context = context if context else SettingsContext()

        self.db_source = context.db_source  # default db source is COLLECTED_DB_SOURCE
        self._required_models = context.required_models
        self._tab_pages_list = context.tab_pages_list
        self._blocking_mode = context.blocking_mode  # Whether the dialog can only be accepted on valid DB connections or not
        self._action_type = context.action_type  # By default "config"
        self.setWindowTitle(context.title)

        self._db = None
        self.init_db_engine = None
        self.dbs_supported = ConfigDBsSupported()
        self._open_dlg_import_schema = False  # After accepting, if non-valid DB is configured, we can go to import schema

        self.online_models_radio_button.setEnabled(
            False)  # This option is disabled until we have online models back!
        self.online_models_radio_button.setChecked(True)
        self.online_models_radio_button.toggled.connect(
            self.model_provider_toggle)
        self.custom_model_directories_line_edit.setText("")
        self.custom_models_dir_button.clicked.connect(
            self.show_custom_model_dir)
        self.custom_model_directories_line_edit.setVisible(False)
        self.custom_models_dir_button.setVisible(False)

        # Set connections
        self.buttonBox.accepted.disconnect()
        self.buttonBox.accepted.connect(self.accepted)
        self.buttonBox.helpRequested.connect(self.show_help)
        self.finished.connect(self.finished_slot)
        self.btn_test_connection.clicked.connect(self.test_connection)
        self.btn_test_ladm_col_structure.clicked.connect(
            self.test_ladm_col_structure)

        self.btn_test_service.clicked.connect(self.test_service)
        self.btn_test_service_transitional_system.clicked.connect(
            self.test_service_transitional_system)
        self.txt_service_endpoint.textEdited.connect(
            self.source_service_endpoint_changed)  # For manual changes only

        self.btn_default_value_sources.clicked.connect(
            self.set_default_value_source_service)
        self.btn_default_value_transitional_system.clicked.connect(
            self.set_default_value_transitional_system_service)

        self.chk_use_roads.toggled.connect(self.update_images_state)

        self.bar = QgsMessageBar()
        self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.layout().addWidget(self.bar, 0, 0, Qt.AlignTop)

        self.cbo_db_engine.clear()

        self._lst_db = self.dbs_supported.get_db_factories()
        self._lst_panel = dict()

        for key, value in self._lst_db.items():
            self.cbo_db_engine.addItem(value.get_name(), key)
            self._lst_panel[key] = value.get_config_panel(self)
            self._lst_panel[key].notify_message_requested.connect(
                self.show_message)
            self.db_layout.addWidget(self._lst_panel[key])

        self.db_engine_changed()

        # Trigger some default behaviours
        self.restore_db_source_settings(
        )  # restore settings with default db source
        self.restore_settings()

        self.roles = RoleRegistry()
        self.load_roles()

        self.cbo_db_engine.currentIndexChanged.connect(self.db_engine_changed)
        self.rejected.connect(self.close_dialog)

        self._update_tabs()

        if context.tip:
            self.show_tip(context.tip)

    def set_db_source(self, db_source):
        self.db_source = db_source
        self.restore_db_source_settings()

    def set_tab_pages_list(self, tab_pages_list):
        self._tab_pages_list = tab_pages_list
        self._update_tabs()

    def set_required_models(self, required_models):
        self._required_models = required_models

    def set_blocking_mode(self, block):
        self._blocking_mode = block

    def _update_tabs(self):
        """
        Show only those tabs that are listed in tab_pages_list, if any. If it's an empty list, show all tabs.
        """
        if self._tab_pages_list:
            for i in reversed(range(self.tabWidget.count())):
                if i not in self._tab_pages_list:
                    self.tabWidget.removeTab(i)

    def load_roles(self):
        """
        Initialize group box for selecting the active role
        """
        self.gbx_active_role_layout = QVBoxLayout()
        dict_roles = self.roles.get_roles_info()
        checked = False
        active_role = self.roles.get_active_role()

        # Initialize radio buttons
        for k, v in dict_roles.items():
            radio = QRadioButton(v)
            radio.setToolTip(self.roles.get_role_description(k))

            if not checked:
                if k == active_role:
                    radio.setChecked(True)
                    checked = True

            self.gbx_active_role_layout.addWidget(radio)

        self.gbx_active_role.setLayout(self.gbx_active_role_layout)

    def close_dialog(self):
        self.close()

    def showEvent(self, event):
        # It is necessary to reload the variables
        # to load the database and schema name
        self.restore_settings()

        self.btn_test_ladm_col_structure.setVisible(
            self._action_type != EnumDbActionType.SCHEMA_IMPORT)

    def model_provider_toggle(self):
        if self.offline_models_radio_button.isChecked():
            self.custom_model_directories_line_edit.setVisible(True)
            self.custom_models_dir_button.setVisible(True)
        else:
            self.custom_model_directories_line_edit.setVisible(False)
            self.custom_models_dir_button.setVisible(False)
            self.custom_model_directories_line_edit.setText("")

    def _get_db_connector_from_gui(self):
        current_db_engine = self.cbo_db_engine.currentData()
        params = self._lst_panel[current_db_engine].read_connection_parameters(
        )
        db = self._lst_db[current_db_engine].get_db_connector(params)
        return db

    def get_db_connection(self):
        if self._db is not None:
            self.logger.info(__name__, "Returning existing db connection...")
        else:
            self.logger.info(__name__, "Getting new db connection...")
            self._db = self._get_db_connector_from_gui()
            self._db.open_connection()

        return self._db

    def show_custom_model_dir(self):
        dlg = CustomModelDirDialog(
            self.custom_model_directories_line_edit.text(), self)
        dlg.exec_()

    def accepted(self):
        """
        We start checking the document repository configuration and only allow to continue if we have a valid repo or
        if the repo won't be used.

        Then, check if connection to DB/schema is valid, if not, block the dialog.
        If valid, check it complies with LADM. If not, block the dialog. If it complies, we have two options: To emit
        db_connection changed or not. Finally, we store options in QSettings.
        """
        res_doc_repo, msg_doc_repo = self.check_document_repository_before_saving_settings(
        )
        if not res_doc_repo:
            self.show_message(msg_doc_repo, Qgis.Warning, 0)
            return  # Do not close the dialog

        ladm_col_schema = False

        db = self._get_db_connector_from_gui()

        test_level = EnumTestLevel.DB_SCHEMA

        if self._action_type == EnumDbActionType.SCHEMA_IMPORT:
            # Limit the validation (used in GeoPackage)
            test_level |= EnumTestLevel.SCHEMA_IMPORT

        res, code, msg = db.test_connection(
            test_level
        )  # No need to pass required_models, we don't test that much

        if res:
            if self._action_type != EnumDbActionType.SCHEMA_IMPORT:
                # Only check LADM-schema if we are not in an SCHEMA IMPORT.
                # We know in an SCHEMA IMPORT, at this point the schema is still not LADM.
                ladm_col_schema, code, msg = db.test_connection(
                    EnumTestLevel.LADM, required_models=self._required_models)

            if not ladm_col_schema and self._action_type != EnumDbActionType.SCHEMA_IMPORT:
                if self._blocking_mode:
                    self.show_message(msg, Qgis.Warning)
                    return  # Do not close the dialog

        else:
            if self._blocking_mode:
                self.show_message(msg, Qgis.Warning)
                return  # Do not close the dialog

        # Connection is valid and complies with LADM
        current_db_engine = self.cbo_db_engine.currentData()
        if self._lst_panel[current_db_engine].state_changed(
        ) or self.init_db_engine != current_db_engine:
            # Emit db_connection_changed
            if self._db is not None:
                self._db.close_connection()

            self._db = db

            # Update db connect with new db conn
            self.conn_manager.set_db_connector_for_source(
                self._db, self.db_source)

            # Emmit signal when db source changes
            self.db_connection_changed.emit(self._db, ladm_col_schema,
                                            self.db_source)
            self.logger.debug(
                __name__, "Settings dialog emitted a db_connection_changed.")

        if not ladm_col_schema and self._action_type == EnumDbActionType.CONFIG:
            msg_box = QMessageBox(self)
            msg_box.setIcon(QMessageBox.Question)
            msg_box.setText(
                QCoreApplication.translate(
                    "SettingsDialog",
                    "No LADM-COL DB has been configured! You'll continue with limited functionality until you configure a LADM-COL DB.\n\nDo you want to go to 'Create LADM-COL structure' dialog?"
                ))
            msg_box.setWindowTitle(
                QCoreApplication.translate("SettingsDialog", "Important"))
            msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.Ignore)
            msg_box.setDefaultButton(QMessageBox.Ignore)
            msg_box.button(QMessageBox.Yes).setText(
                QCoreApplication.translate("SettingsDialog",
                                           "Yes, go to create structure"))
            msg_box.button(QMessageBox.Ignore).setText(
                QCoreApplication.translate("SettingsDialog",
                                           "No, I'll do it later"))
            reply = msg_box.exec_()

            if reply == QMessageBox.Yes:
                self._open_dlg_import_schema = True  # We will open it when we've closed this Settings dialog

        # If active role is changed (a check and confirmation may be needed), refresh the GUI
        # Note: Better to leave this check as the last one in the accepted() method.
        selected_role = self.get_selected_role()
        if self.roles.get_active_role() != selected_role:
            b_change_role = True
            if STSession().is_user_logged():
                reply = QMessageBox.question(
                    self.parent,
                    QCoreApplication.translate("SettingsDialog", "Warning"),
                    QCoreApplication.translate(
                        "SettingsDialog",
                        "You have a ST connection opened and you want to change your role.\nIf you confirm that you want to change your role, you'll be logged out from the ST.\n\nDo you really want to change your role?"
                    ), QMessageBox.Yes | QMessageBox.Cancel,
                    QMessageBox.Cancel)
                if reply == QMessageBox.Yes:
                    STSession().logout()
                elif reply == QMessageBox.Cancel:
                    # No need to switch back selected role, the Settings Dialog gets it from role registry
                    b_change_role = False

            if b_change_role:
                self.logger.info(
                    __name__,
                    "The active role has changed from '{}' to '{}'.".format(
                        self.roles.get_active_role(), selected_role))
                self.roles.set_active_role(
                    selected_role
                )  # Emits signal that refreshed the plugin for this role

        self.save_settings(db)

        QDialog.accept(self)
        self.close()

        if self._open_dlg_import_schema:
            # After Settings dialog has been closed, we could call Import Schema depending on user's answer above
            self.open_dlg_import_schema.emit(Context())
            self.logger.debug(
                __name__,
                "Settings dialog emitted a show Import Schema dialog.")

    def check_document_repository_before_saving_settings(self):
        # Check if source service is checked (active). If so, check if either status or endpoint changed. If so,
        # check if self._valid_document_repository is False. If so, we need to test the service and only allow to save
        # if such test is successful.
        res, msg = True, ''
        if self.connection_box.isChecked(
        ):  # The user wants to have the source service enabled
            initial_config = QSettings().value(
                'Asistente-LADM-COL/sources/use_service',
                DEFAULT_USE_SOURCE_SERVICE_SETTING, bool)
            initial_endpoint = QSettings().value(
                'Asistente-LADM-COL/sources/service_endpoint',
                DEFAULT_ENDPOINT_SOURCE_SERVICE)

            # Config changed or Endpoint changed?
            if initial_config != self.connection_box.isChecked(
            ) or initial_endpoint.strip() != self.txt_service_endpoint.text(
            ).strip():
                if not self._valid_document_repository:  # A test service has not been run, so we need to do it now
                    self.logger.debug(
                        __name__,
                        "The user wants to enable the source service but the 'test service' has not been run on the current URL. Testing it..."
                    )
                    res_test, msg_test = self.test_service()
                    if not res_test:
                        res = False
                        msg = QCoreApplication.translate(
                            "SettingsDialog",
                            "The source service is not valid, so it cannot be activated! Adjust such configuration before saving settings."
                        )

        return res, msg

    def source_service_endpoint_changed(self, new_text):
        # Source service endpoint was changed, so a test_service is required to make the valid variable True
        self._valid_document_repository = False

    def get_selected_role(self):
        selected_role = None
        radio_checked = None
        for i in range(self.gbx_active_role_layout.count()):
            radio = self.gbx_active_role_layout.itemAt(i).widget()
            if radio.isChecked():
                radio_checked = radio.text()
                break

        for k, v in self.roles.get_roles_info().items():
            if v == radio_checked:
                selected_role = k
                break

        return selected_role  # Role key

    def reject(self):
        self.done(0)

    def finished_slot(self, result):
        self.bar.clearWidgets()

    def save_settings(self, db):
        settings = QSettings()
        current_db_engine = self.cbo_db_engine.currentData()
        settings.setValue(
            'Asistente-LADM-COL/db/{db_source}/db_connection_engine'.format(
                db_source=self.db_source), current_db_engine)
        dict_conn = self._lst_panel[
            current_db_engine].read_connection_parameters()

        self._lst_db[current_db_engine].save_parameters_conn(
            dict_conn=dict_conn, db_source=self.db_source)

        settings.setValue(
            'Asistente-LADM-COL/models/custom_model_directories_is_checked',
            self.offline_models_radio_button.isChecked())
        if self.offline_models_radio_button.isChecked():
            settings.setValue('Asistente-LADM-COL/models/custom_models',
                              self.custom_model_directories_line_edit.text())

        self.app.settings.tolerance = self.sbx_tolerance.value()
        settings.setValue('Asistente-LADM-COL/quality/use_roads',
                          self.chk_use_roads.isChecked())

        settings.setValue(
            'Asistente-LADM-COL/models/validate_data_importing_exporting',
            self.chk_validate_data_importing_exporting.isChecked())

        endpoint_transitional_system = self.txt_service_transitional_system.text(
        ).strip()
        settings.setValue(
            'Asistente-LADM-COL/sources/service_transitional_system',
            (endpoint_transitional_system[:-1]
             if endpoint_transitional_system.endswith('/') else
             endpoint_transitional_system)
            or TransitionalSystemConfig().ST_DEFAULT_DOMAIN)

        settings.setValue('Asistente-LADM-COL/sources/use_service',
                          self.connection_box.isChecked())
        endpoint = self.txt_service_endpoint.text().strip()
        settings.setValue(
            'Asistente-LADM-COL/sources/service_endpoint',
            (endpoint[:-1] if endpoint.endswith('/') else endpoint)
            or DEFAULT_ENDPOINT_SOURCE_SERVICE)

        settings.setValue(
            'Asistente-LADM-COL/automatic_values/automatic_values_in_batch_mode',
            self.chk_automatic_values_in_batch_mode.isChecked())

        # Changes in automatic namespace, local_id or t_ili_tid configuration?
        current_namespace_enabled = settings.value(
            'Asistente-LADM-COL/automatic_values/namespace_enabled', True,
            bool)
        current_namespace_prefix = settings.value(
            'Asistente-LADM-COL/automatic_values/namespace_prefix', "")
        current_local_id_enabled = settings.value(
            'Asistente-LADM-COL/automatic_values/local_id_enabled', True, bool)
        current_t_ili_tid_enabled = settings.value(
            'Asistente-LADM-COL/automatic_values/t_ili_tid_enabled', True,
            bool)

        settings.setValue(
            'Asistente-LADM-COL/automatic_values/namespace_enabled',
            self.namespace_collapsible_group_box.isChecked())
        if self.namespace_collapsible_group_box.isChecked():
            settings.setValue(
                'Asistente-LADM-COL/automatic_values/namespace_prefix',
                self.txt_namespace.text())

        settings.setValue(
            'Asistente-LADM-COL/automatic_values/local_id_enabled',
            self.chk_local_id.isChecked())
        settings.setValue(
            'Asistente-LADM-COL/automatic_values/t_ili_tid_enabled',
            self.chk_t_ili_tid.isChecked())

        if current_namespace_enabled != self.namespace_collapsible_group_box.isChecked() or \
           current_namespace_prefix != self.txt_namespace.text() or \
           current_local_id_enabled != self.chk_local_id.isChecked() or \
           current_t_ili_tid_enabled != self.chk_t_ili_tid.isChecked():
            if db is not None:
                self.logger.info(
                    __name__,
                    "Automatic values changed in Settings dialog. All LADM-COL layers are being updated..."
                )
                self.app.core.automatic_fields_settings_changed(db)

    def restore_db_source_settings(self):
        settings = QSettings()
        default_db_engine = self.dbs_supported.id_default_db

        self.init_db_engine = settings.value(
            'Asistente-LADM-COL/db/{db_source}/db_connection_engine'.format(
                db_source=self.db_source), default_db_engine)
        index_db_engine = self.cbo_db_engine.findData(self.init_db_engine)

        if index_db_engine == -1:
            index_db_engine = self.cbo_db_engine.findData(default_db_engine)

        self.cbo_db_engine.setCurrentIndex(index_db_engine)
        self.db_engine_changed()

        # restore db settings for all panels
        for db_engine, db_factory in self._lst_db.items():
            dict_conn = db_factory.get_parameters_conn(self.db_source)
            self._lst_panel[db_engine].write_connection_parameters(dict_conn)
            self._lst_panel[db_engine].save_state()

    def restore_settings(self):
        # Restore QSettings
        settings = QSettings()

        custom_model_directories_is_checked = settings.value(
            'Asistente-LADM-COL/models/custom_model_directories_is_checked',
            DEFAULT_USE_CUSTOM_MODELS,
            type=bool)
        if custom_model_directories_is_checked:
            self.offline_models_radio_button.setChecked(True)
            self.custom_model_directories_line_edit.setText(
                settings.value('Asistente-LADM-COL/models/custom_models',
                               DEFAULT_MODELS_DIR))
            self.custom_model_directories_line_edit.setVisible(True)
            self.custom_models_dir_button.setVisible(True)
        else:
            self.online_models_radio_button.setChecked(True)
            self.custom_model_directories_line_edit.setText("")
            self.custom_model_directories_line_edit.setVisible(False)
            self.custom_models_dir_button.setVisible(False)

        self.sbx_tolerance.setValue(self.app.settings.tolerance)
        use_roads = settings.value('Asistente-LADM-COL/quality/use_roads',
                                   True, bool)
        self.chk_use_roads.setChecked(use_roads)
        self.update_images_state(use_roads)

        self.chk_automatic_values_in_batch_mode.setChecked(
            settings.value(
                'Asistente-LADM-COL/automatic_values/automatic_values_in_batch_mode',
                DEFAULT_AUTOMATIC_VALUES_IN_BATCH_MODE, bool))
        self.connection_box.setChecked(
            settings.value('Asistente-LADM-COL/sources/use_service',
                           DEFAULT_USE_SOURCE_SERVICE_SETTING, bool))
        self.namespace_collapsible_group_box.setChecked(
            settings.value(
                'Asistente-LADM-COL/automatic_values/namespace_enabled', True,
                bool))
        self.chk_local_id.setChecked(
            settings.value(
                'Asistente-LADM-COL/automatic_values/local_id_enabled', True,
                bool))
        self.chk_t_ili_tid.setChecked(
            settings.value(
                'Asistente-LADM-COL/automatic_values/t_ili_tid_enabled', True,
                bool))
        self.txt_namespace.setText(
            str(
                settings.value(
                    'Asistente-LADM-COL/automatic_values/namespace_prefix',
                    "")))

        self.chk_validate_data_importing_exporting.setChecked(
            settings.value(
                'Asistente-LADM-COL/models/validate_data_importing_exporting',
                True, bool))

        self.txt_service_transitional_system.setText(
            settings.value(
                'Asistente-LADM-COL/sources/service_transitional_system',
                TransitionalSystemConfig().ST_DEFAULT_DOMAIN))
        self.txt_service_endpoint.setText(
            settings.value('Asistente-LADM-COL/sources/service_endpoint',
                           DEFAULT_ENDPOINT_SOURCE_SERVICE))

    def db_engine_changed(self):
        if self._db is not None:
            self._db.close_connection()

        self._db = None  # Reset db connection

        for key, value in self._lst_panel.items():
            value.setVisible(False)

        current_db_engine = self.cbo_db_engine.currentData()

        self._lst_panel[current_db_engine].setVisible(True)

    def test_connection(self):
        db = self._get_db_connector_from_gui()
        test_level = EnumTestLevel.DB_SCHEMA

        if self._action_type == EnumDbActionType.SCHEMA_IMPORT:
            test_level |= EnumTestLevel.SCHEMA_IMPORT

        res, code, msg = db.test_connection(
            test_level
        )  # No need to pass required_models, we don't test that much

        if db is not None:
            db.close_connection()

        self.show_message(msg, Qgis.Info if res else Qgis.Warning)
        self.logger.info(__name__, "Test connection!")
        self.logger.debug(
            __name__,
            "Test connection ({}): {}, {}".format(test_level, res, msg))

    def test_ladm_col_structure(self):
        db = self._get_db_connector_from_gui()
        res, code, msg = db.test_connection(
            test_level=EnumTestLevel.LADM,
            required_models=self._required_models)

        if db is not None:
            db.close_connection()

        self.show_message(msg, Qgis.Info if res else Qgis.Warning)
        self.logger.info(__name__, "Test LADM structure!")
        self.logger.debug(
            __name__,
            "Test connection ({}): {}, {}".format(EnumTestLevel.LADM, res,
                                                  msg))

    def test_service(self):
        self.setEnabled(False)
        QCoreApplication.processEvents()
        res, msg = self.app.core.is_source_service_valid(
            self.txt_service_endpoint.text().strip())
        self._valid_document_repository = res  # Required to be True if the user wants to enable the source service
        self.setEnabled(True)
        self.show_message(msg['text'], msg['level'], 0)
        return res, msg

    def test_service_transitional_system(self):
        self.setEnabled(False)
        QCoreApplication.processEvents()
        res, msg = self.app.core.is_transitional_system_service_valid(
            self.txt_service_transitional_system.text().strip())
        self.setEnabled(True)
        self.show_message(msg['text'], msg['level'])

    def set_default_value_source_service(self):
        self.txt_service_endpoint.setText(DEFAULT_ENDPOINT_SOURCE_SERVICE)

    def set_default_value_transitional_system_service(self):
        self.txt_service_transitional_system.setText(
            TransitionalSystemConfig().ST_DEFAULT_DOMAIN)

    def show_message(self, message, level, duration=10):
        self.bar.clearWidgets(
        )  # Remove previous messages before showing a new one
        self.bar.pushMessage(message, level, duration)

    def show_tip(self, tip):
        self.show_message(tip, Qgis.Info,
                          0)  # Don't show counter for the tip message

    def update_images_state(self, checked):
        self.img_with_roads.setEnabled(checked)
        self.img_with_roads.setToolTip(
            QCoreApplication.translate(
                "SettingsDialog", "Missing roads will be marked as errors."
            ) if checked else '')
        self.img_without_roads.setEnabled(not checked)
        self.img_without_roads.setToolTip(
            '' if checked else QCoreApplication.translate(
                "SettingsDialog", "Missing roads will not be marked as errors."
            ))

    def show_help(self):
        show_plugin_help("settings")

    def set_action_type(self, action_type):
        self._action_type = action_type

        for key, value in self._lst_panel.items():
            value.set_action(action_type)
Example #22
0
    def get_ladm_queries(self, engine):
        if engine not in self._ladm_queries:
            self._ladm_queries[engine] = ConfigDBsSupported().get_db_factory(
                engine).get_ladm_queries()

        return self._ladm_queries[engine]
Example #23
0
    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()
Example #24
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)