Пример #1
0
    def __init__(self, db):
        QObject.__init__(self)
        self.app = AppInterface()
        self.logger = Logger()
        self.__db = db

        self.__tr_dict = TranslatableConfigStrings(
        ).get_translatable_config_strings()

        # Hierarquical dict of qrs and qr groups
        self.__qrs_tree_data = dict()  # {type: {qr_key1: qr_obj1, ...}, ...}

        # Hierarquical dict of qrs and qr groups with general results
        self.__general_results_tree_data = dict(
        )  # {type: {qr_obj1: qr_results1, ...}, ...}

        # Hierarchical dict of qrs and their corresponding error instances
        # feature1: {uuids, rel_uuids, error_type, nombre_ili_obj, details, values, fixed, exception, geom_fks}
        self.__error_results_data = dict()  # {qr_key1: {t_id1: feature1}}

        self.__qr_results_dir_path = ''  # Dir path where results will be stored
        self.__selected_qrs = list()  # QRs to be validated (at least 1)
        self.__selected_qr = None  # QR selected by the user to show its corresponding errors (exactly 1)

        self.__qr_engine = None  # Once set, we can reuse it
        self.__qrs_results = None  # QualityRulesExecutionResult object

        # To cache layers from QR DB
        self.__error_layer = None
        self.__point_layer = None
        self.__line_layer = None
        self.__polygon_layer = None

        # Cache by t_id (built on demand): {t_id1: 'Error', t_id2: 'Corregido', t_id3: 'Exception'}
        self.__error_state_dict = dict()
Пример #2
0
    def __init__(self, db, layers, editing_layer):
        self._db = db
        self.__layers = layers
        self.__translatable_config_strings = TranslatableConfigStrings()
        self.width_line = 1.0

        self._editing_layer = editing_layer
        self.app = None
Пример #3
0
    def decorated_function(*args, **kwargs):
        inst = args[0] if type(
            args[0]).__name__ == 'AsistenteLADMCOLPlugin' else args[0].ladmcol
        context = args[1]

        for db_source in context.get_db_sources():
            db = inst.conn_manager.get_db_connector_from_source(
                db_source=db_source)
            db.test_connection()
            if not db.cadastral_cartography_model_exists():
                widget = inst.iface.messageBar().createMessage(
                    "Asistente LADM-COL",
                    QCoreApplication.translate(
                        "AsistenteLADMCOLPlugin",
                        "Check your {} database connection. The '{} {}' model is required for this functionality, but could not be found in your current database. Click the button to go to Settings."
                    ).format(
                        Tr.tr_db_source(db_source),
                        LADMColModelRegistry().model(
                            LADMNames.CADASTRAL_CARTOGRAPHY_MODEL_KEY).alias(),
                        LADMColModelRegistry().model(
                            LADMNames.CADASTRAL_CARTOGRAPHY_MODEL_KEY).alias())
                )
                button = QPushButton(widget)
                button.setText(
                    QCoreApplication.translate("AsistenteLADMCOLPlugin",
                                               "Settings"))

                settings_context = SettingsContext(db_source)
                settings_context.required_models = [
                    LADMNames.CADASTRAL_CARTOGRAPHY_MODEL_KEY
                ]
                settings_context.tab_pages_list = [
                    SETTINGS_CONNECTION_TAB_INDEX
                ]
                settings_context.title = QCoreApplication.translate(
                    "SettingsDialog", "{} Connection Settings").format(
                        Tr.tr_db_source(db_source))
                settings_context.tip = QCoreApplication.translate(
                    "SettingsDialog",
                    "Set a DB connection with the '{}' model.").format(
                        LADMColModelRegistry().model(
                            LADMNames.CADASTRAL_CARTOGRAPHY_MODEL_KEY).alias())
                button.pressed.connect(
                    partial(inst.show_settings_clear_message_bar,
                            settings_context))

                widget.layout().addWidget(button)
                inst.iface.messageBar().pushWidget(widget, Qgis.Warning, 15)
                inst.logger.warning(
                    __name__,
                    QCoreApplication.translate(
                        "AsistenteLADMCOLPlugin",
                        "A dialog/tool couldn't be opened/executed, connection to DB was not valid."
                    ))
                return

        func_to_decorate(*args, **kwargs)
Пример #4
0
    def __init__(self):
        self.logger = Logger()
        self.__quality_rules_data = QualityRuleConfig.get_quality_rules_config(
        )
        self.__translated_strings = TranslatableConfigStrings(
        ).get_translatable_config_strings()
        self._quality_rule_groups = dict()
        self.__quality_rules = dict()

        self.role_registry = RoleRegistry()

        self._initialize_quality_rule_manager()
Пример #5
0
class RightOfWayManager:

    def __init__(self, db, layers, editing_layer):
        self._db = db
        self.__layers = layers
        self.__translatable_config_strings = TranslatableConfigStrings()
        self.width_line = 1.0

        self._editing_layer = editing_layer
        self.app = None

    def finish_feature_creation(self, layerId, features):
        fid = features[0].id()
        is_valid = False
        feature_tid = None

        if self._editing_layer.getFeature(fid).isValid():
            is_valid = True
            feature_tid = self._editing_layer.getFeature(fid)[self._db.names.T_ID_F]

        return FinishFeatureCreationArgs(is_valid, feature_tid)

    def get_memory_line_layer(self, base_layer):
        translated_strings = self.__translatable_config_strings.get_translatable_config_strings()
        # Add Memory line layer
        temporal_layer = QgsVectorLayer(
            "MultiLineString?crs={}".format(get_crs_authid(base_layer.sourceCrs())),
            translated_strings[RIGHT_OF_WAY_LINE_LAYER], "memory")

        return temporal_layer

    def get_feature_with_buffer_right_of_way(self, tmp_layer, layer):
        params = {'INPUT': tmp_layer,
                  'DISTANCE': self.width_line,
                  'SEGMENTS': 5,
                  'END_CAP_STYLE': 1,  # Flat
                  'JOIN_STYLE': 2,
                  'MITER_LIMIT': 2,
                  'DISSOLVE': False,
                  'OUTPUT': 'memory:'}
        buffered_right_of_way_layer = processing.run("native:buffer", params)['OUTPUT']
        buffer_geometry = buffered_right_of_way_layer.getFeature(1).geometry()
        feature = QgsVectorLayerUtils().createFeature(layer, buffer_geometry)
        tmp_layer.commitChanges()

        return feature

    def add_tmp_feature_to_layer(self, layer, tmp_feature):
        # Add temporal geometry create
        if not layer.isEditable():
            layer.startEditing()

        self.app.core.suppress_form(layer, True)

        layer.addFeature(tmp_feature)
    def get_quality_error_group_names():
        root = QgsProject.instance().layerTreeRoot()
        prefix = TranslatableConfigStrings.get_translatable_config_strings(
        )[ERROR_LAYER_GROUP_PREFIX]
        error_group_names = list()

        for group in root.findGroups(False):
            if group.name().startswith(prefix):
                error_group_names.append(group.name())

        return error_group_names
    def get_quality_error_group(timestamp, create_if_non_existent=True):
        root = QgsProject.instance().layerTreeRoot()
        prefix = TranslatableConfigStrings.get_translatable_config_strings(
        )[ERROR_LAYER_GROUP_PREFIX]
        group_name = "{} {}".format(prefix, timestamp)

        group = root.findGroup(group_name)
        if group is None and create_if_non_existent:
            group = root.insertGroup(0, group_name)
            ilg = qgis.utils.plugins['InvisibleLayersAndGroups']
            ilg.hideGroup(group)
            group.setExpanded(False)

        return group
Пример #8
0
    def __init__(self, iface, db, qgis_utils, wizard_settings):
        super(AbsWizardFactory, self).__init__()
        self.iface = iface
        self._db = db
        self.qgis_utils = qgis_utils
        self.wizard_config = wizard_settings
        self.logger = Logger()
        self.names = self._db.names
        self.help_strings = HelpStrings()
        self.translatable_config_strings = TranslatableConfigStrings()
        load_ui(self.wizard_config[WIZARD_UI], self)

        self.WIZARD_FEATURE_NAME = self.wizard_config[WIZARD_FEATURE_NAME]
        self.WIZARD_TOOL_NAME = self.wizard_config[WIZARD_TOOL_NAME]
        self.EDITING_LAYER_NAME = self.wizard_config[WIZARD_EDITING_LAYER_NAME]
        self._layers = self.wizard_config[WIZARD_LAYERS]
        self.set_ready_only_field()

        self.init_gui()
Пример #9
0
    def get_indicators_config(self, node_name, node_type):
        """
        Gets the configuration of layer tree node indicators. Each node could have several indicators.

        :param node_name: Layer tree node name
        :param node_type: QgsLayerTreeNode.NodeType
        :return: List of indicators data. Each indicator config data is a dict, which has these mandatory keys:
                    INDICATOR_TOOLTIP,
                    INDICATOR_ICON,
                    INDICATOR_SLOT
        """
        indicators_config = []
        translated_strings = TranslatableConfigStrings.get_translatable_config_strings(
        )

        if node_type == QgsLayerTreeNode.NodeGroup:
            if node_name == translated_strings[ERROR_LAYER_GROUP]:
                indicators_config = [{
                    INDICATOR_TOOLTIP:
                    QCoreApplication.translate(
                        "LayerTreeIndicatorConfig",
                        "<b>Export</b><br>Export quality errors to GeoPackage"
                    ),
                    INDICATOR_ICON:
                    QIcon(":/Asistente-LADM-COL/resources/images/save.svg"),
                    INDICATOR_SLOT:
                    self._slot_caller.export_error_group
                }, {
                    INDICATOR_TOOLTIP:
                    QCoreApplication.translate(
                        "LayerTreeIndicatorConfig",
                        "<b>Export</b><br>Export quality errors to PDF"),
                    INDICATOR_ICON:
                    QIcon(":/Asistente-LADM-COL/resources/images/pdf.svg"),
                    INDICATOR_SLOT:
                    self._slot_caller.show_log_quality_dialog
                }]
        elif node_type == QgsLayerTreeNode.NodeLayer:
            pass

        return indicators_config
Пример #10
0
 def get_error_layers_group(self):
     """
     Get the topology errors group. If it exists but is placed in another
     position rather than the top, it moves the group to the top.
     """
     root = QgsProject.instance().layerTreeRoot()
     translated_strings = TranslatableConfigStrings.get_translatable_config_strings(
     )
     group = root.findGroup(translated_strings[ERROR_LAYER_GROUP])
     if group is None:
         group = root.insertGroup(0, translated_strings[ERROR_LAYER_GROUP])
         self.add_indicators_requested.emit(
             translated_strings[ERROR_LAYER_GROUP],
             QgsLayerTreeNode.NodeGroup)
     elif not self.iface.layerTreeView().layerTreeModel().node2index(
             group).row() == 0 or type(group.parent()) is QgsLayerTreeGroup:
         group_clone = group.clone()
         root.insertChildNode(0, group_clone)
         parent = group.parent()
         parent.removeChildNode(group)
         group = group_clone
     return group
    def __init__(self, db, qgis_utils, quality, parent=None):
        QDialog.__init__(self, parent)
        self.setupUi(self)
        self._db = db
        self.qgis_utils = qgis_utils
        self.quality = quality
        self.names = self._db.names
        self.translatable_config_strings = TranslatableConfigStrings()

        self.trw_quality_rules.setItemsExpandable(False)
        self.trw_quality_rules.itemSelectionChanged.connect(
            self.validate_selection_rules)
        self.trw_quality_rules.itemSelectionChanged.emit()

        # Set connections
        self.buttonBox.accepted.connect(self.accepted)
        self.buttonBox.rejected.connect(self.rejected)
        self.buttonBox.helpRequested.connect(self.show_help)
        self.btn_select_all.clicked.connect(self.select_all)
        self.btn_clear_selection.clicked.connect(self.clear_selection)

        translated_strings = self.translatable_config_strings.get_translatable_config_strings(
        )

        self.items_dict = collections.OrderedDict()
        self.items_dict[QCoreApplication.translate(
            "QualityDialog", "Rules for Points"
        )] = {
            'icon':
            'points',
            'rules': [{
                'id':
                'check_overlaps_in_boundary_points',
                'text':
                translated_strings[CHECK_OVERLAPS_IN_BOUNDARY_POINTS]
            }, {
                'id':
                'check_overlaps_in_control_points',
                'text':
                translated_strings[CHECK_OVERLAPS_IN_CONTROL_POINTS]
            }, {
                'id':
                'check_boundary_points_covered_by_boundary_nodes',
                'text':
                translated_strings[
                    CHECK_BOUNDARY_POINTS_COVERED_BY_BOUNDARY_NODES]
            }, {
                'id':
                'check_boundary_points_covered_by_plot_nodes',
                'text':
                translated_strings[CHECK_BOUNDARY_POINTS_COVERED_BY_PLOT_NODES]
            }]
        }
        self.items_dict[QCoreApplication.translate(
            "QualityDialog", "Rules for Lines")] = {
                'icon':
                'lines',
                'rules': [{
                    'id':
                    'check_overlaps_in_boundaries',
                    'text':
                    translated_strings[CHECK_OVERLAPS_IN_BOUNDARIES]
                }, {
                    'id':
                    'check_boundaries_are_not_split',
                    'text':
                    translated_strings[CHECK_BOUNDARIES_ARE_NOT_SPLIT]
                }, {
                    'id':
                    'check_boundaries_covered_by_plots',
                    'text':
                    translated_strings[CHECK_BOUNDARIES_COVERED_BY_PLOTS]
                }, {
                    'id':
                    'check_boundary_nodes_covered_by_boundary_points',
                    'text':
                    translated_strings[
                        CHECK_BOUNDARY_NODES_COVERED_BY_BOUNDARY_POINTS]
                }, {
                    'id':
                    'check_dangles_in_boundaries',
                    'text':
                    translated_strings[CHECK_DANGLES_IN_BOUNDARIES]
                }]
            }
        self.items_dict[QCoreApplication.translate(
            "QualityDialog", "Rules for Polygons"
        )] = {
            'icon':
            'polygons',
            'rules': [
                {
                    'id': 'check_overlaps_in_plots',
                    'text': translated_strings[CHECK_OVERLAPS_IN_PLOTS]
                },
                {
                    'id': 'check_overlaps_in_buildings',
                    'text': translated_strings[CHECK_OVERLAPS_IN_BUILDINGS]
                },
                {
                    'id': 'check_overlaps_in_rights_of_way',
                    'text': translated_strings[CHECK_OVERLAPS_IN_RIGHTS_OF_WAY]
                },
                {
                    'id': 'check_plots_covered_by_boundaries',
                    'text':
                    translated_strings[CHECK_PLOTS_COVERED_BY_BOUNDARIES]
                    #}, {
                    #    'id': 'check_missing_survey_points_in_buildings',
                    #    'text': QCoreApplication.translate("QualityDialog", "Buildings nodes should be covered by Survey Points")
                },
                {
                    'id':
                    'check_right_of_way_overlaps_buildings',
                    'text':
                    translated_strings[CHECK_RIGHT_OF_WAY_OVERLAPS_BUILDINGS]
                },
                {
                    'id': 'check_gaps_in_plots',
                    'text': translated_strings[CHECK_GAPS_IN_PLOTS]
                },
                {
                    'id': 'check_multipart_in_right_of_way',
                    'text': translated_strings[CHECK_MULTIPART_IN_RIGHT_OF_WAY]
                },
                {
                    'id':
                    'check_plot_nodes_covered_by_boundary_points',
                    'text':
                    translated_strings[
                        CHECK_PLOT_NODES_COVERED_BY_BOUNDARY_POINTS]
                },
                {
                    'id': 'check_buildings_should_be_within_plots',
                    'text': translated_strings[CHECK_BUILDING_WITHIN_PLOTS]
                },
                {
                    'id': 'check_building_units_should_be_within_plots',
                    'text':
                    translated_strings[CHECK_BUILDING_UNIT_WITHIN_PLOTS]
                }
            ]
        }

        self.items_dict[QCoreApplication.translate(
            "QualityDialog", "Logic consistency rules")] = {
                'icon':
                'tables',
                'rules': [{
                    'id':
                    'check_parcel_right_relationship',
                    'text':
                    translated_strings[CHECK_PARCEL_RIGHT_RELATIONSHIP]
                }, {
                    'id':
                    'find_duplicate_records_in_a_table',
                    'text':
                    translated_strings[FIND_DUPLICATE_RECORDS_IN_A_TABLE]
                }, {
                    'id':
                    'check_fraction_sum_for_party_groups',
                    'text':
                    translated_strings[CHECK_FRACTION_SUM_FOR_PARTY_GROUPS]
                }, {
                    'id':
                    'check_department_code_has_two_numerical_characters',
                    'text':
                    translated_strings[
                        CHECK_DEPARMENT_CODE_HAS_TWO_NUMERICAL_CHARACTERS]
                }, {
                    'id':
                    'check_municipality_code_has_three_numerical_characters',
                    'text':
                    translated_strings[
                        CHECK_MUNICIPALITY_CODE_HAS_THREE_NUMERICAL_CHARACTERS]
                }, {
                    'id':
                    'check_parcel_number_has_30_numerical_characters',
                    'text':
                    translated_strings[
                        CHECK_PARCEL_NUMBER_HAS_30_NUMERICAL_CHARACTERS]
                }, {
                    'id':
                    'check_parcel_number_before_has_20_numerical_characters',
                    'text':
                    translated_strings[
                        CHECK_PARCEL_NUMBER_BEFORE_HAS_20_NUMERICAL_CHARACTERS]
                }, {
                    'id':
                    'check_col_party_natural_type',
                    'text':
                    translated_strings[CHECK_COL_PARTY_NATURAL_TYPE]
                }, {
                    'id':
                    'check_col_party_legal_type',
                    'text':
                    translated_strings[CHECK_COL_PARTY_LEGAL_TYPE]
                }, {
                    'id':
                    'check_parcel_type_and_22_position_of_parcel_number',
                    'text':
                    translated_strings[
                        CHECK_PARCEL_TYPE_AND_22_POSITON_OF_PARCEL_NUMBER]
                }, {
                    'id': 'check_uebaunit_parcel',
                    'text': translated_strings[CHECK_UEBAUNIT_PARCEL]
                }]
            }

        self.load_items()
class QualityDialog(QDialog, DIALOG_UI):
    def __init__(self, db, qgis_utils, quality, parent=None):
        QDialog.__init__(self, parent)
        self.setupUi(self)
        self._db = db
        self.qgis_utils = qgis_utils
        self.quality = quality
        self.names = self._db.names
        self.translatable_config_strings = TranslatableConfigStrings()

        self.trw_quality_rules.setItemsExpandable(False)
        self.trw_quality_rules.itemSelectionChanged.connect(
            self.validate_selection_rules)
        self.trw_quality_rules.itemSelectionChanged.emit()

        # Set connections
        self.buttonBox.accepted.connect(self.accepted)
        self.buttonBox.rejected.connect(self.rejected)
        self.buttonBox.helpRequested.connect(self.show_help)
        self.btn_select_all.clicked.connect(self.select_all)
        self.btn_clear_selection.clicked.connect(self.clear_selection)

        translated_strings = self.translatable_config_strings.get_translatable_config_strings(
        )

        self.items_dict = collections.OrderedDict()
        self.items_dict[QCoreApplication.translate(
            "QualityDialog", "Rules for Points"
        )] = {
            'icon':
            'points',
            'rules': [{
                'id':
                'check_overlaps_in_boundary_points',
                'text':
                translated_strings[CHECK_OVERLAPS_IN_BOUNDARY_POINTS]
            }, {
                'id':
                'check_overlaps_in_control_points',
                'text':
                translated_strings[CHECK_OVERLAPS_IN_CONTROL_POINTS]
            }, {
                'id':
                'check_boundary_points_covered_by_boundary_nodes',
                'text':
                translated_strings[
                    CHECK_BOUNDARY_POINTS_COVERED_BY_BOUNDARY_NODES]
            }, {
                'id':
                'check_boundary_points_covered_by_plot_nodes',
                'text':
                translated_strings[CHECK_BOUNDARY_POINTS_COVERED_BY_PLOT_NODES]
            }]
        }
        self.items_dict[QCoreApplication.translate(
            "QualityDialog", "Rules for Lines")] = {
                'icon':
                'lines',
                'rules': [{
                    'id':
                    'check_overlaps_in_boundaries',
                    'text':
                    translated_strings[CHECK_OVERLAPS_IN_BOUNDARIES]
                }, {
                    'id':
                    'check_boundaries_are_not_split',
                    'text':
                    translated_strings[CHECK_BOUNDARIES_ARE_NOT_SPLIT]
                }, {
                    'id':
                    'check_boundaries_covered_by_plots',
                    'text':
                    translated_strings[CHECK_BOUNDARIES_COVERED_BY_PLOTS]
                }, {
                    'id':
                    'check_boundary_nodes_covered_by_boundary_points',
                    'text':
                    translated_strings[
                        CHECK_BOUNDARY_NODES_COVERED_BY_BOUNDARY_POINTS]
                }, {
                    'id':
                    'check_dangles_in_boundaries',
                    'text':
                    translated_strings[CHECK_DANGLES_IN_BOUNDARIES]
                }]
            }
        self.items_dict[QCoreApplication.translate(
            "QualityDialog", "Rules for Polygons"
        )] = {
            'icon':
            'polygons',
            'rules': [
                {
                    'id': 'check_overlaps_in_plots',
                    'text': translated_strings[CHECK_OVERLAPS_IN_PLOTS]
                },
                {
                    'id': 'check_overlaps_in_buildings',
                    'text': translated_strings[CHECK_OVERLAPS_IN_BUILDINGS]
                },
                {
                    'id': 'check_overlaps_in_rights_of_way',
                    'text': translated_strings[CHECK_OVERLAPS_IN_RIGHTS_OF_WAY]
                },
                {
                    'id': 'check_plots_covered_by_boundaries',
                    'text':
                    translated_strings[CHECK_PLOTS_COVERED_BY_BOUNDARIES]
                    #}, {
                    #    'id': 'check_missing_survey_points_in_buildings',
                    #    'text': QCoreApplication.translate("QualityDialog", "Buildings nodes should be covered by Survey Points")
                },
                {
                    'id':
                    'check_right_of_way_overlaps_buildings',
                    'text':
                    translated_strings[CHECK_RIGHT_OF_WAY_OVERLAPS_BUILDINGS]
                },
                {
                    'id': 'check_gaps_in_plots',
                    'text': translated_strings[CHECK_GAPS_IN_PLOTS]
                },
                {
                    'id': 'check_multipart_in_right_of_way',
                    'text': translated_strings[CHECK_MULTIPART_IN_RIGHT_OF_WAY]
                },
                {
                    'id':
                    'check_plot_nodes_covered_by_boundary_points',
                    'text':
                    translated_strings[
                        CHECK_PLOT_NODES_COVERED_BY_BOUNDARY_POINTS]
                },
                {
                    'id': 'check_buildings_should_be_within_plots',
                    'text': translated_strings[CHECK_BUILDING_WITHIN_PLOTS]
                },
                {
                    'id': 'check_building_units_should_be_within_plots',
                    'text':
                    translated_strings[CHECK_BUILDING_UNIT_WITHIN_PLOTS]
                }
            ]
        }

        self.items_dict[QCoreApplication.translate(
            "QualityDialog", "Logic consistency rules")] = {
                'icon':
                'tables',
                'rules': [{
                    'id':
                    'check_parcel_right_relationship',
                    'text':
                    translated_strings[CHECK_PARCEL_RIGHT_RELATIONSHIP]
                }, {
                    'id':
                    'find_duplicate_records_in_a_table',
                    'text':
                    translated_strings[FIND_DUPLICATE_RECORDS_IN_A_TABLE]
                }, {
                    'id':
                    'check_fraction_sum_for_party_groups',
                    'text':
                    translated_strings[CHECK_FRACTION_SUM_FOR_PARTY_GROUPS]
                }, {
                    'id':
                    'check_department_code_has_two_numerical_characters',
                    'text':
                    translated_strings[
                        CHECK_DEPARMENT_CODE_HAS_TWO_NUMERICAL_CHARACTERS]
                }, {
                    'id':
                    'check_municipality_code_has_three_numerical_characters',
                    'text':
                    translated_strings[
                        CHECK_MUNICIPALITY_CODE_HAS_THREE_NUMERICAL_CHARACTERS]
                }, {
                    'id':
                    'check_parcel_number_has_30_numerical_characters',
                    'text':
                    translated_strings[
                        CHECK_PARCEL_NUMBER_HAS_30_NUMERICAL_CHARACTERS]
                }, {
                    'id':
                    'check_parcel_number_before_has_20_numerical_characters',
                    'text':
                    translated_strings[
                        CHECK_PARCEL_NUMBER_BEFORE_HAS_20_NUMERICAL_CHARACTERS]
                }, {
                    'id':
                    'check_col_party_natural_type',
                    'text':
                    translated_strings[CHECK_COL_PARTY_NATURAL_TYPE]
                }, {
                    'id':
                    'check_col_party_legal_type',
                    'text':
                    translated_strings[CHECK_COL_PARTY_LEGAL_TYPE]
                }, {
                    'id':
                    'check_parcel_type_and_22_position_of_parcel_number',
                    'text':
                    translated_strings[
                        CHECK_PARCEL_TYPE_AND_22_POSITON_OF_PARCEL_NUMBER]
                }, {
                    'id': 'check_uebaunit_parcel',
                    'text': translated_strings[CHECK_UEBAUNIT_PARCEL]
                }]
            }

        self.load_items()

    def validate_selection_rules(self):
        # At least one quality rule must have been selected
        self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(
            bool(self.trw_quality_rules.selectedItems()))

    def load_items(self):
        self.trw_quality_rules.setUpdatesEnabled(
            False)  # Don't render until we're ready
        self.trw_quality_rules.clear()

        font = QFont()
        font.setBold(True)

        for group, items in self.items_dict.items():
            children = []
            group_item = QTreeWidgetItem([group])
            group_item.setData(0, Qt.BackgroundRole,
                               QBrush(QColor(219, 219, 219, 255)))
            group_item.setData(0, Qt.FontRole, font)
            icon = QIcon(":/Asistente-LADM_COL/resources/images/{}.png".format(
                items['icon']))
            group_item.setData(0, Qt.DecorationRole, icon)

            for rule in items['rules']:
                rule_item = QTreeWidgetItem([rule['text']])
                rule_item.setData(0, Qt.UserRole, rule['id'])

                children.append(rule_item)

            group_item.addChildren(children)
            self.trw_quality_rules.addTopLevelItem(group_item)

        # Make group items non selectable and expanded
        for i in range(self.trw_quality_rules.topLevelItemCount()):
            self.trw_quality_rules.topLevelItem(i).setFlags(
                Qt.ItemIsEnabled)  # Not selectable
            self.trw_quality_rules.topLevelItem(i).setExpanded(True)

        self.trw_quality_rules.setUpdatesEnabled(True)  # Now render!

    def accepted(self):
        # we erase the group error layer every time it runs because we assume that data set changes.
        self.qgis_utils.remove_error_group_requested.emit()
        self.quality.initialize_log_dialog_quality()
        selected_count = len(self.trw_quality_rules.selectedItems())

        if selected_count > 0:
            self.quality.set_count_topology_rules(selected_count)
        translated_strings = self.translatable_config_strings.get_translatable_config_strings(
        )

        iterator = QTreeWidgetItemIterator(self.trw_quality_rules,
                                           QTreeWidgetItemIterator.Selectable)
        while iterator.value():
            item = iterator.value()

            if item.isSelected():
                id = item.data(0, Qt.UserRole)
                rule_name = item.text(0)

                # NOTE: Do not remove the named parameters, this is needed for making a decorator that thinks they are
                # optional happy!
                if id == 'check_overlaps_in_boundary_points':
                    self.quality.check_overlapping_points(
                        self._db,
                        point_layer_name=self.names.OP_BOUNDARY_POINT_T,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_overlaps_in_control_points':
                    self.quality.check_overlapping_points(
                        self._db,
                        point_layer_name=self.names.OP_CONTROL_POINT_T,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_boundary_points_covered_by_boundary_nodes':
                    self.quality.check_boundary_points_covered_by_boundary_nodes(
                        self._db,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_boundary_points_covered_by_plot_nodes':
                    self.quality.check_boundary_points_covered_by_plot_nodes(
                        self._db,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_overlaps_in_boundaries':
                    self.quality.check_overlaps_in_boundaries(
                        self._db,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_boundaries_are_not_split':
                    self.quality.check_boundaries_are_not_split(
                        self._db,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_boundaries_covered_by_plots':
                    self.quality.check_boundaries_covered_by_plots(
                        self._db,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_boundary_nodes_covered_by_boundary_points':
                    self.quality.check_boundary_nodes_covered_by_boundary_points(
                        self._db,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_dangles_in_boundaries':
                    self.quality.check_dangles_in_boundaries(
                        self._db,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_overlaps_in_plots':
                    self.quality.check_overlapping_polygons(
                        self._db,
                        polygon_layer_name=self.names.OP_PLOT_T,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_overlaps_in_buildings':
                    self.quality.check_overlapping_polygons(
                        self._db,
                        polygon_layer_name=self.names.OP_BUILDING_T,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_overlaps_in_rights_of_way':
                    self.quality.check_overlapping_polygons(
                        self._db,
                        polygon_layer_name=self.names.OP_RIGHT_OF_WAY_T,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_plots_covered_by_boundaries':
                    self.quality.check_plots_covered_by_boundaries(
                        self._db,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                #elif id == 'check_missing_survey_points_in_buildings':
                #    self.quality.check_missing_survey_points_in_buildings(self._db)
                elif id == 'check_right_of_way_overlaps_buildings':
                    self.quality.check_right_of_way_overlaps_buildings(
                        self._db,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_gaps_in_plots':
                    self.quality.check_gaps_in_plots(
                        self._db,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_multipart_in_right_of_way':
                    self.quality.check_multiparts_in_right_of_way(
                        self._db,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_plot_nodes_covered_by_boundary_points':
                    self.quality.check_plot_nodes_covered_by_boundary_points(
                        self._db,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_buildings_should_be_within_plots':
                    self.quality.check_building_within_plots(
                        self._db,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_building_units_should_be_within_plots':
                    self.quality.check_building_unit_within_plots(
                        self._db,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'check_parcel_right_relationship':
                    self.quality.check_parcel_right_relationship(
                        self._db,
                        rule_name=rule_name,
                        translated_strings=translated_strings)
                elif id == 'find_duplicate_records_in_a_table':
                    self.quality.find_duplicate_records_in_a_table(
                        self._db, rule_name=rule_name)
                elif id == 'check_fraction_sum_for_party_groups':
                    self.quality.check_fraction_sum_for_party_groups(
                        self._db, rule_name=rule_name)
                elif id == 'check_department_code_has_two_numerical_characters':
                    self.quality.basic_logic_validations(
                        self._db,
                        rule='DEPARTMENT_CODE_VALIDATION',
                        rule_name=rule_name)
                elif id == 'check_municipality_code_has_three_numerical_characters':
                    self.quality.basic_logic_validations(
                        self._db,
                        rule='MUNICIPALITY_CODE_VALIDATION',
                        rule_name=rule_name)
                elif id == 'check_parcel_number_has_30_numerical_characters':
                    self.quality.basic_logic_validations(
                        self._db,
                        rule='PARCEL_NUMBER_VALIDATION',
                        rule_name=rule_name)
                elif id == 'check_parcel_number_before_has_20_numerical_characters':
                    self.quality.basic_logic_validations(
                        self._db,
                        rule='PARCEL_NUMBER_BEFORE_VALIDATION',
                        rule_name=rule_name)
                elif id == 'check_col_party_natural_type':
                    self.quality.advanced_logic_validations(
                        self._db,
                        rule='COL_PARTY_TYPE_NATURAL_VALIDATION',
                        rule_name=rule_name)
                elif id == 'check_col_party_legal_type':
                    self.quality.advanced_logic_validations(
                        self._db,
                        rule='COL_PARTY_TYPE_NO_NATURAL_VALIDATION',
                        rule_name=rule_name)
                elif id == 'check_parcel_type_and_22_position_of_parcel_number':
                    self.quality.advanced_logic_validations(
                        self._db,
                        rule=
                        'PARCEL_TYPE_AND_22_POSITION_OF_PARCEL_NUMBER_VALIDATION',
                        rule_name=rule_name)
                elif id == 'check_uebaunit_parcel':
                    self.quality.advanced_logic_validations(
                        self._db,
                        rule='UEBAUNIT_PARCEL_VALIDATION',
                        rule_name=rule_name)

            iterator += 1

        if selected_count > 0:
            self.quality.generate_log_button()

        if self.qgis_utils.error_group_exists():
            group = self.qgis_utils.get_error_layers_group()
            # # Check if group layer is empty
            if group.findLayers():
                self.qgis_utils.set_error_group_visibility(True)
            else:
                self.qgis_utils.remove_error_group_requested.emit()

    def rejected(self):
        pass

    def select_all(self):
        self.trw_quality_rules.selectAll()

    def clear_selection(self):
        self.trw_quality_rules.clearSelection()

    def show_help(self):
        self.qgis_utils.show_help("quality_rules")
Пример #13
0
class Symbology:
    ERROR_LAYER = 'error_layer'

    def __init__(self):
        self.translatable_config_strings = TranslatableConfigStrings()

    def get_default_style_group(self, names):
         return {
            names.OP_BOUNDARY_T: {
                QgsWkbTypes.LineGeometry: 'style_boundary'
            },
            names.OP_BOUNDARY_POINT_T: {
                QgsWkbTypes.PointGeometry: 'style_boundary_point'
            },
            names.OP_SURVEY_POINT_T: {
                QgsWkbTypes.PointGeometry: 'style_survey_point'
            },
            names.OP_CONTROL_POINT_T: {
                QgsWkbTypes.PointGeometry: 'style_control_point'
            },
            names.OP_PLOT_T: {
                QgsWkbTypes.PointGeometry: 'style_plot_point',
                QgsWkbTypes.PolygonGeometry: 'style_plot_polygon'
            },
            names.OP_BUILDING_T: {
                QgsWkbTypes.PointGeometry: 'style_building_point',
                QgsWkbTypes.PolygonGeometry: 'style_building'
            },
            names.OP_BUILDING_UNIT_T: {
                QgsWkbTypes.PointGeometry: 'style_building_unit_point',
                QgsWkbTypes.PolygonGeometry: 'style_building_unit_25'
            },
            names.OP_RIGHT_OF_WAY_T: {
                QgsWkbTypes.PointGeometry: 'style_right_of_way_point',
                QgsWkbTypes.PolygonGeometry: 'style_right_of_way'
            },
            self.ERROR_LAYER: {
                QgsWkbTypes.PointGeometry: 'style_point_error',
                QgsWkbTypes.LineGeometry: 'style_line_error',
                QgsWkbTypes.PolygonGeometry: 'style_polygon_error'
            }
        }

    def get_supplies_style_group(self, names):
        return {
            names.GC_PLOT_T: {
                QgsWkbTypes.PolygonGeometry: 'style_supplies_plot_polygon'
            }
        }

    def get_custom_error_layers(self):
        translated_strings = self.translatable_config_strings.get_translatable_config_strings()

        return {
            translated_strings[CHECK_BOUNDARIES_COVERED_BY_PLOTS]: {
                'es': 'style_boundary_should_be_covered_by_plot_es',
                'en': 'style_boundary_should_be_covered_by_plot_en'
            },
            translated_strings[CHECK_PLOTS_COVERED_BY_BOUNDARIES]: {
                'es': 'style_plot_should_be_covered_by_boundary_es',
                'en': 'style_plot_should_be_covered_by_boundary_en'
            },
            translated_strings[CHECK_BOUNDARY_POINTS_COVERED_BY_BOUNDARY_NODES]: {
                'es': 'style_boundary_points_should_be_covered_by_boundary_nodes_es',
                'en': 'style_boundary_points_should_be_covered_by_boundary_nodes_en'
            },
            translated_strings[CHECK_BOUNDARY_NODES_COVERED_BY_BOUNDARY_POINTS]: {
                'es': 'style_boundary_nodes_should_be_covered_by_boundary_points_es',
                'en': 'style_boundary_nodes_should_be_covered_by_boundary_points_en'
             }
        }

    def get_error_layer_name(self):
        return self.ERROR_LAYER
Пример #14
0
 def __init__(self):
     self.translatable_config_strings = TranslatableConfigStrings()
Пример #15
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
Пример #16
0
class QualityRuleManager(QObject, metaclass=SingletonQObject):
    def __init__(self):
        self.logger = Logger()
        self.__quality_rules_data = QualityRuleConfig.get_quality_rules_config(
        )
        self.__translated_strings = TranslatableConfigStrings(
        ).get_translatable_config_strings()
        self._quality_rule_groups = dict()
        self.__quality_rules = dict()

        self.role_registry = RoleRegistry()

        self._initialize_quality_rule_manager()

    def _initialize_quality_rule_manager(self):
        for group_k, group_v in self.__quality_rules_data.items():
            self._quality_rule_groups[group_k] = group_v[QUALITY_GROUP_NAME]

            for rule_k, rule_v in group_v[QUALITY_RULES].items():
                self.__quality_rules[rule_k] = QualityRule(rule_v)
        self.logger.info(
            __name__,
            "{} quality rules registered!".format(len(self.__quality_rules)))

    def get_quality_rule(self, rule_key):
        """
        Returns the QualityRule object corresponding to a rule code.

        :param rule_key: rule key
        :return: QualityRule
        """
        return self.__quality_rules.get(rule_key)

    def get_quality_rule_group_name(self, group_key):
        """
        Returns a quality rule group name.

        :param group_key: Group key
        :return: Group name if the group key is found. Otherwise, None.
        """
        return self._quality_rule_groups.get(group_key)

    def get_quality_rules_by_group(self, enum_group=None):
        """
        Returns all rules in a given group. If no enum_group is given,
        it returns the whole set of rules classified by group.

        :param enum_group:  EnumQualityRule.Point|Line|Polygon|Logic
        :return: dict of rules
        """
        quality_rules_group = dict()
        role_key = self.role_registry.get_active_role()
        role_quality_rules = self.role_registry.get_role_quality_rules(
            role_key)

        if enum_group:
            quality_rules_group = {
                k_rule: v_rule
                for k_rule, v_rule in self.__quality_rules.items()
                if k_rule in enum_group and k_rule in role_quality_rules
            }
        else:
            quality_rules_group[EnumQualityRule.Point] = dict()
            quality_rules_group[EnumQualityRule.Line] = dict()
            quality_rules_group[EnumQualityRule.Polygon] = dict()
            quality_rules_group[EnumQualityRule.Logic] = dict()

            for k_quality_rule, v_quality_rule in self.__quality_rules.items():
                if k_quality_rule in role_quality_rules:
                    if k_quality_rule in EnumQualityRule.Point:
                        quality_rules_group[EnumQualityRule.Point][
                            k_quality_rule] = v_quality_rule
                    elif k_quality_rule in EnumQualityRule.Line:
                        quality_rules_group[EnumQualityRule.Line][
                            k_quality_rule] = v_quality_rule
                    elif k_quality_rule in EnumQualityRule.Polygon:
                        quality_rules_group[EnumQualityRule.Polygon][
                            k_quality_rule] = v_quality_rule
                    elif k_quality_rule in EnumQualityRule.Logic:
                        quality_rules_group[EnumQualityRule.Logic][
                            k_quality_rule] = v_quality_rule

            self.logger.debug(
                __name__, "Quality Rules for role '{}': {}".format(
                    role_key,
                    ", ".join([str(rqr.value) for rqr in role_quality_rules])))

        return quality_rules_group

    def get_error_message(self, error_code):
        return self.__translated_strings.get(error_code)
Пример #17
0
class QualityRuleController(QObject):

    open_report_called = pyqtSignal(QualityRuleResultLog)  # log result
    quality_rule_layer_removed = pyqtSignal()
    refresh_error_layer_symbology = pyqtSignal(QgsVectorLayer)
    total_progress_changed = pyqtSignal(int)  # Progress value

    def __init__(self, db):
        QObject.__init__(self)
        self.app = AppInterface()
        self.logger = Logger()
        self.__db = db

        self.__tr_dict = TranslatableConfigStrings(
        ).get_translatable_config_strings()

        # Hierarquical dict of qrs and qr groups
        self.__qrs_tree_data = dict()  # {type: {qr_key1: qr_obj1, ...}, ...}

        # Hierarquical dict of qrs and qr groups with general results
        self.__general_results_tree_data = dict(
        )  # {type: {qr_obj1: qr_results1, ...}, ...}

        # Hierarchical dict of qrs and their corresponding error instances
        # feature1: {uuids, rel_uuids, error_type, nombre_ili_obj, details, values, fixed, exception, geom_fks}
        self.__error_results_data = dict()  # {qr_key1: {t_id1: feature1}}

        self.__qr_results_dir_path = ''  # Dir path where results will be stored
        self.__selected_qrs = list()  # QRs to be validated (at least 1)
        self.__selected_qr = None  # QR selected by the user to show its corresponding errors (exactly 1)

        self.__qr_engine = None  # Once set, we can reuse it
        self.__qrs_results = None  # QualityRulesExecutionResult object

        # To cache layers from QR DB
        self.__error_layer = None
        self.__point_layer = None
        self.__line_layer = None
        self.__polygon_layer = None

        # Cache by t_id (built on demand): {t_id1: 'Error', t_id2: 'Corregido', t_id3: 'Exception'}
        self.__error_state_dict = dict()

    def get_tr_string(self, key):
        return self.__tr_dict.get(key, key)

    def validate_qrs(self):
        if self.__qr_engine is None:
            self.__qr_engine = QualityRuleEngine(self.__db,
                                                 self.__selected_qrs,
                                                 self.app.settings.tolerance,
                                                 self.__qr_results_dir_path)
            self.__qr_engine.progress_changed.connect(
                self.total_progress_changed)
        else:
            self.__qr_engine.initialize(self.__db, self.__selected_qrs,
                                        self.app.settings.tolerance,
                                        self.__qr_results_dir_path)
        #self.__qr_engine.qr_logger.show_message_emitted.connect(self.show_log_quality_message)
        #self.__qr_engine.qr_logger.show_button_emitted.connect(self.show_log_quality_button)
        #self.__qr_engine.qr_logger.set_initial_progress_emitted.connect(self.set_log_quality_initial_progress)
        #self.__qr_engine.qr_logger.set_final_progress_emitted.connect(self.set_log_quality_final_progress)

        use_roads = bool(QSettings().value(
            'Asistente-LADM-COL/quality/use_roads', DEFAULT_USE_ROADS_VALUE,
            bool))
        options = {QR_IGACR3006: {'use_roads': use_roads}}

        res, msg, qrs_res = self.__qr_engine.validate_quality_rules(options)
        if not res:
            return res, msg, None

        self.__qrs_results = qrs_res

        self.__connect_layer_willbedeleted_signals(
        )  # Note: Call it after validate_quality_rules!

        res_u, msg_u, output_qr_dir = QualityErrorDBUtils.get_quality_validation_output_path(
            self.__qr_results_dir_path, self.__qr_engine.get_timestamp())

        if len(self.__selected_qrs) == 1:
            pre_text = QCoreApplication.translate(
                "QualityRules", "The quality rule was checked!")
        else:
            pre_text = QCoreApplication.translate(
                "QualityRules",
                "All the {} quality rules were checked!").format(
                    len(self.__selected_qrs))

        post_text = QCoreApplication.translate(
            "QualityRules",
            "Both a PDF report and a GeoPackage database with errors can be found in <a href='file:///{}'>{}</a>."
        ).format(normalize_local_url(output_qr_dir), output_qr_dir)

        self.logger.success_msg(__name__, "{} {}".format(pre_text, post_text))

        self.__emit_refresh_error_layer_symbology()

        return res, msg, self.__qrs_results

    def __connect_layer_willbedeleted_signals(self):
        """
        Iterate QR DB layers from the layer tree and connect their layerwillberemoved signals.
        If a QR DB layer is removed, we'll react in the GUI.
        """
        group = QualityErrorDBUtils.get_quality_error_group(
            self.__qr_engine.get_timestamp())

        if group:
            for tree_layer in group.findLayers():
                try:
                    tree_layer.layer().willBeDeleted.disconnect(
                        self.quality_rule_layer_removed)
                except:
                    pass
                tree_layer.layer().willBeDeleted.connect(
                    self.quality_rule_layer_removed)

    def disconnect_layer_willberemoved_signals(self):
        group = QualityErrorDBUtils.get_quality_error_group(
            self.__qr_engine.get_timestamp(), False)

        if group:
            for tree_layer in group.findLayers():
                try:
                    tree_layer.layer().willBeDeleted.disconnect(
                        self.quality_rule_layer_removed)
                except:
                    pass

    def get_qr_result(self, qr_key):
        """
        Return the QRExecutionResult object for the given qr_key.

        It first attempts to find it in the __qrs_results dict, but, chances are,
        the whole set of QRs hasn't been validated when this method is called,
        so, as a last resort, we go for the tree_data, which is updated each time
        a QR gets its result.
        """
        if self.__qrs_results is not None:
            return self.__qrs_results.result(qr_key)

        for type, qr_dict in self.__general_results_tree_data.items():
            for k, v in qr_dict.items():
                if k.id() == qr_key:
                    return self.__general_results_tree_data[type][k]

        return None

    def __reset_qrs_results(self):
        # To be used when we are returning to select QRs (i.e., to the initial panel)
        self.__qrs_results = None

    def __get_qrs_per_role_and_models(self):
        return QualityRuleRegistry().get_qrs_per_role_and_models(self.__db)

    def load_tree_data(self, mode):
        """
        Builds a hierarchical dict by qr type: {qr_type1: {qr_key1: qr_obj1, ...}, ...}

        Tree data for panel 1.

        :params mode: Value from EnumQualityRulePanelMode (either VALIDATE or READ).
                      For VALIDATE we load QRs from registry (filtered by role and current db models).
                      For READ we load QRs from the DB itself.
        """
        if mode == EnumQualityRulePanelMode.VALIDATE:
            qrs = self.__get_qrs_per_role_and_models(
            )  # Dict of qr key and qr objects.
        else:
            qrs = dict()  # TODO: Read QRs from the QR DB

        for qr_key, qr_obj in qrs.items():
            type = qr_obj.type()
            if type not in self.__qrs_tree_data:
                self.__qrs_tree_data[type] = {qr_key: qr_obj}
            else:
                self.__qrs_tree_data[type][qr_key] = qr_obj

    def get_qrs_tree_data(self):
        return self.__qrs_tree_data

    def set_qr_dir_path(self, path):
        self.__qr_results_dir_path = path

    def set_selected_qrs(self, selected_qrs):
        # We sort them because the engine needs the QRs sorted for the PDF report
        for type, qr_dict in self.__qrs_tree_data.items():
            for qr_key, qr_obj in qr_dict.items():
                if qr_key in selected_qrs:
                    self.__selected_qrs.append(qr_key)

    def get_selected_qrs(self):
        return self.__selected_qrs

    def __reset_selected_qrs(self):
        # To be used when we are returning to select QRs (i.e., to the initial panel)
        self.__selected_qrs = list()

    def reset_vars_for_general_results_panel(self):
        # Initialize variables when we leave the general results panel
        self.__reset_general_results_tree_data()
        self.__reset_selected_qrs()
        self.__reset_qrs_results()
        self.__reset_layers()

        # Call it before removing QR DB group to avoid triggering parent.layer_removed() slot again.
        self.disconnect_layer_willberemoved_signals()

        # When we leave the GRP, we remove the QR DB group from layer tree,
        # because we won't be working anymore with that QR DB
        QualityErrorDBUtils.remove_quality_error_group(
            self.__qr_engine.get_timestamp())

    def reset_vars_for_error_results_panel(self):
        # Initialize variables when we leave the error results panel
        self.__reset_error_results_data()
        self.__reset_selected_qr()
        self.__reset_error_state_dict()
        self.__reset_layers()

    def load_general_results_tree_data(self):
        """
        Builds a hierarchical dict by qr type: {type: {qr_obj1: qr_results1, ...}, ...}

        Tree data for panel 2.
        """
        for type, qr_dict in self.__qrs_tree_data.items():
            for qr_key, qr_obj in qr_dict.items():
                if qr_key in self.__selected_qrs:
                    if type not in self.__general_results_tree_data:
                        self.__general_results_tree_data[type] = {qr_obj: None}
                    else:
                        self.__general_results_tree_data[type][qr_obj] = None

    def get_general_results_tree_data(self):
        return self.__general_results_tree_data

    def __reset_general_results_tree_data(self):
        # To be used when we are returning to select QRs (i.e., to the initial panel)
        self.__general_results_tree_data = dict()

    def set_qr_validation_result(self, qr, qr_result):
        """
        When a QR has its validation result after validation,
        we can store it in our custom dict by using this method.
        """
        for type, qr_dict in self.__general_results_tree_data.items():
            for k, v in qr_dict.items():
                if k == qr:
                    self.__general_results_tree_data[type][k] = qr_result

    def open_report(self):
        if self.__qr_engine:
            log_result = self.__qr_engine.qr_logger.get_log_result()
            self.open_report_called.emit(log_result)

    def set_selected_qr(self, qr_key):
        self.__selected_qr = QualityRuleRegistry().get_quality_rule(qr_key)
        return self.__selected_qr is not None  # We should not be able to continue if we don't find the QR

    def get_selected_qr(self):
        return self.__selected_qr

    def load_error_results_data(self):
        """
        Go to table and bring data to the dict.
        We should keep this dict updated with changes from the user.
        From time to time we reflect this dict changes in the original data source.
        """
        db = self.__qr_engine.get_db_quality()
        names = db.names

        layers = {names.ERR_QUALITY_ERROR_T: None, names.ERR_RULE_TYPE_T: None}
        self.app.core.get_layers(db, layers, load=False)
        if not layers:
            self.logger.critical(
                __name__,
                "Quality error layers ('{}') not found!".format(",".join(
                    list(layers.keys()))))
            return

        # First go for the selected quality error's t_id
        features = LADMData.get_features_from_t_ids(
            layers[names.ERR_RULE_TYPE_T], names.ERR_RULE_TYPE_T_CODE_F,
            [self.__selected_qr.id()])
        t_id = features[0][names.T_ID_F] if features else None
        if not t_id:
            self.logger.critical(
                __name__, "Quality error rule ('{}') not found!".format(
                    self.__selected_qr.id()))
            return

        # Now go for all features that match the selected quality rule
        features = LADMData.get_features_from_t_ids(
            layers[names.ERR_QUALITY_ERROR_T],
            names.ERR_QUALITY_ERROR_T_RULE_TYPE_F, [t_id])

        self.__error_results_data[self.__selected_qr.id()] = {
            feature[names.T_ID_F]: feature
            for feature in features
        }

    def get_error_results_data(self):
        # Get the subdict {t_id1: feature1, ...} corresponding to selected qr
        return self.__error_results_data.get(
            self.__selected_qr.id() if self.__selected_qr else '', dict())

    def __reset_error_results_data(self):
        # To be used when we are returning to select QR results (i.e., to the general results panel)
        self.__error_results_data = dict()

    def error_t_id(self, feature):
        return feature[self.__qr_engine.get_db_quality().names.T_ID_F]

    def is_fixed_error(self, feature):
        db = self.__qr_engine.get_db_quality()
        state_t_id = feature[db.names.ERR_QUALITY_ERROR_T_ERROR_STATE_F]
        return self.__get_error_state_value(
            state_t_id) == LADMNames.ERR_ERROR_STATE_D_FIXED_V

    def is_error(self, feature):
        db = self.__qr_engine.get_db_quality()
        state_t_id = feature[db.names.ERR_QUALITY_ERROR_T_ERROR_STATE_F]
        return self.__get_error_state_value(
            state_t_id) == LADMNames.ERR_ERROR_STATE_D_ERROR_V

    def is_exception(self, feature):
        db = self.__qr_engine.get_db_quality()
        state_t_id = feature[db.names.ERR_QUALITY_ERROR_T_ERROR_STATE_F]
        return self.__get_error_state_value(
            state_t_id) == LADMNames.ERR_ERROR_STATE_D_EXCEPTION_V

    def uuid_objs(self, feature):
        return "\n".join(feature[self.__qr_engine.get_db_quality().names.
                                 ERR_QUALITY_ERROR_T_OBJECT_IDS_F])

    def ili_obj_name(self, feature):
        ili_name = feature[self.__qr_engine.get_db_quality().names.
                           ERR_QUALITY_ERROR_T_ILI_NAME_F]
        return ili_name.split(".")[-1] if ili_name else ''

    def error_type_code_and_display(self, feature):
        db = self.__qr_engine.get_db_quality()
        names = db.names
        layer = self.app.core.get_layer(db, names.ERR_ERROR_TYPE_T, load=False)
        features = LADMData.get_features_from_t_ids(
            layer, names.T_ID_F,
            [feature[db.names.ERR_QUALITY_ERROR_T_ERROR_TYPE_F]])  # tid

        return features[0][
            names.
            ERR_ERROR_TYPE_T_CODE_F] if features else QCoreApplication.translate(
                "QualityRules", "No error type found!"
            ), features[0][
                names.
                ERR_ERROR_TYPE_T_DESCRIPTION_F] if features else QCoreApplication.translate(
                    "QualityRules", "No error description found!")

    def error_details_and_values(self, feature):
        res = ""
        db = self.__qr_engine.get_db_quality()
        details = feature[db.names.ERR_QUALITY_ERROR_T_DETAILS_F]
        values = feature[db.names.ERR_QUALITY_ERROR_T_VALUES_F]

        if details:
            res = details
        if values:
            try:
                res_values = json.loads(values)
                if type(res_values) is dict:
                    items = ""
                    for k, v in res_values.items():
                        items = res + "{}: {}\n".format(k, v)

                    res_values = items.strip()
                else:
                    res_values = str(res_values)
            except json.decoder.JSONDecodeError as e:
                res_values = values

            res = res_values if not res else "{}\n\n{}".format(res, res_values)

        return res

    def error_state(self, feature):
        db = self.__qr_engine.get_db_quality()
        state_t_id = feature[db.names.ERR_QUALITY_ERROR_T_ERROR_STATE_F]
        return self.__get_error_state_value(state_t_id)

    def __get_error_state_value(self, state_t_id):
        if state_t_id not in self.__error_state_dict:
            db = self.__qr_engine.get_db_quality()
            self.__error_state_dict[state_t_id] = LADMData(
            ).get_domain_value_from_code(db, db.names.ERR_ERROR_STATE_D,
                                         state_t_id)

        return self.__error_state_dict.get(state_t_id, "")

    def __get_error_state_t_id(self, state_value):
        # Use __error_state_dict to read cached values, but this time we have the value,
        # not the key, so check in dict values and if not found, go for its t_id
        if state_value not in self.__error_state_dict.values():
            db = self.__qr_engine.get_db_quality()
            t_id = LADMData().get_domain_code_from_value(
                db, db.names.ERR_ERROR_STATE_D, state_value)
            self.__error_state_dict[t_id] = state_value

        # Get key by value in a dict:
        return next((k for k in self.__error_state_dict
                     if self.__error_state_dict[k] == state_value), None)

    def __get_error_layer(self):
        if not self.__error_layer:
            db = self.__qr_engine.get_db_quality()
            self.__error_layer = self.app.core.get_layer(
                db, db.names.ERR_QUALITY_ERROR_T)

        return self.__error_layer

    def __get_point_error_layer(self):
        if not self.__point_layer:
            db = self.__qr_engine.get_db_quality()
            self.__point_layer = self.app.core.get_layer(
                db, db.names.ERR_POINT_T)

        return self.__point_layer

    def __get_line_error_layer(self):
        if not self.__line_layer:
            db = self.__qr_engine.get_db_quality()
            self.__line_layer = self.app.core.get_layer(
                db, db.names.ERR_LINE_T)

        return self.__line_layer

    def __get_polygon_error_layer(self):
        if not self.__polygon_layer:
            db = self.__qr_engine.get_db_quality()
            self.__polygon_layer = self.app.core.get_layer(
                db, db.names.ERR_POLYGON_T)

        return self.__polygon_layer

    def __reset_layers(self):
        # To be used when we are returning to select QR results (i.e., to the general results panel)
        self.__error_layer = None
        self.__point_layer = None
        self.__line_layer = None
        self.__polygon_layer = None

    def __reset_selected_qr(self):
        # To be used when we are returning to select QR results (i.e., to the general results panel)
        self.__selected_qr = None

    def __reset_error_state_dict(self):
        # To be used when we are returning to select QR results (i.e., to the general results panel)
        self.__error_state_dict = dict()

    def __error_related_geometries(self, error_t_ids):
        # Prefered geometry types are polygons, lines, points, in that order
        db = self.__qr_engine.get_db_quality()
        error_data = self.get_error_results_data()
        dict_layer_fids = dict()

        for error_t_id in error_t_ids:
            feature = error_data.get(error_t_id, None)

            if feature:
                polygon = feature[db.names.ERR_QUALITY_ERROR_T_POLYGON_F]
                line = feature[db.names.ERR_QUALITY_ERROR_T_LINE_F]
                point = feature[db.names.ERR_QUALITY_ERROR_T_POINT_F]

                if polygon:
                    if 'polygon' in dict_layer_fids:
                        dict_layer_fids['polygon']['fids'].append(polygon)
                    else:
                        dict_layer_fids['polygon'] = {
                            'layer': self.__get_polygon_error_layer(),
                            'fids': [polygon]
                        }
                elif line:
                    if 'line' in dict_layer_fids:
                        dict_layer_fids['line']['fids'].append(line)
                    else:
                        dict_layer_fids['line'] = {
                            'layer': self.__get_line_error_layer(),
                            'fids': [line]
                        }
                elif point:
                    if 'point' in dict_layer_fids:
                        dict_layer_fids['point']['fids'].append(point)
                    else:
                        dict_layer_fids['point'] = {
                            'layer': self.__get_point_error_layer(),
                            'fids': [point]
                        }

        return dict_layer_fids

    def highlight_geometries(self, t_ids):
        res_geometries = self.__error_related_geometries(t_ids)

        if res_geometries:
            # First zoom to geometries
            if len(res_geometries) == 1:  # Only one geometry type related
                for geom_type, dict_layer_fids in res_geometries.items(
                ):  # We know this will be called just once
                    self.app.gui.zoom_to_feature_ids(dict_layer_fids['layer'],
                                                     dict_layer_fids['fids'])
            else:  # Multiple geometry types were found, so combine the extents and then zoom to it
                combined_extent = QgsRectangle()
                for geom_type, dict_layer_fids in res_geometries.items():
                    combined_extent.combineExtentWith(
                        self.app.core.get_extent_from_feature_ids(
                            dict_layer_fids['layer'], dict_layer_fids['fids']))

                self.app.gui.zoom_to_extent(combined_extent)

            # Now highlight geometries
            for geom_type, dict_layer_fids in res_geometries.items():
                self.app.gui.flash_features(dict_layer_fids['layer'],
                                            dict_layer_fids['fids'],
                                            flashes=5)

    def get_uuids_display_name(self):
        names = self.__qr_engine.get_db_quality().names
        res = self.__selected_qr.field_mapping(names).get(
            names.ERR_QUALITY_ERROR_T_OBJECT_IDS_F, '')

        return res if res else QCoreApplication.translate(
            "QualityRules", "UUIDs")

    def set_fixed_error(self, error_t_id, fixed):
        # Save to the intermediate dict of data and to the underlying data source whether an error is fixed or not
        db = self.__qr_engine.get_db_quality()
        idx_state = self.__get_error_layer().fields().indexOf(
            db.names.ERR_QUALITY_ERROR_T_ERROR_STATE_F)

        value = LADMNames.ERR_ERROR_STATE_D_FIXED_V if fixed else LADMNames.ERR_ERROR_STATE_D_ERROR_V
        fixed_or_error_t_id = self.__get_error_state_t_id(value)

        if fixed_or_error_t_id is None:
            self.logger.critical(
                __name__,
                "The error state t_id couldn't be found for value '{}'!".
                format(value))
            return

        # Save to dict
        self.get_error_results_data()[error_t_id].setAttribute(
            idx_state, fixed_or_error_t_id)

        fids = LADMData.get_fids_from_key_values(self.__get_error_layer(),
                                                 db.names.T_ID_F, [error_t_id])

        # Save to underlying data source
        if fids:
            res = self.__get_error_layer().dataProvider(
            ).changeAttributeValues(
                {fids[0]: {
                     idx_state: fixed_or_error_t_id
                 }})

            if not res:
                self.logger.critical(__name__,
                                     "Error modifying the error state value!")
        else:
            self.logger.critical(
                __name__, "Error with t_id '' not found!".format(error_t_id))

    def __emit_refresh_error_layer_symbology(self):
        if self.__get_point_error_layer().featureCount():
            self.refresh_error_layer_symbology.emit(
                self.__get_point_error_layer())

        if self.__get_line_error_layer().featureCount():
            self.refresh_error_layer_symbology.emit(
                self.__get_line_error_layer())

        if self.__get_polygon_error_layer().featureCount():
            self.refresh_error_layer_symbology.emit(
                self.__get_polygon_error_layer())
Пример #18
0
 def error_group_exists(self):
     root = QgsProject.instance().layerTreeRoot()
     translated_strings = TranslatableConfigStrings.get_translatable_config_strings(
     )
     return root.findGroup(
         translated_strings[ERROR_LAYER_GROUP]) is not None
Пример #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()
Пример #20
0
    def decorated_function(*args, **kwargs):
        """
        For all db_source in the context check:
        1. that db connection is valid, otherwise show message with button that opens db connection setting dialog.
        2. that db connection parameters are equal to db source connection parameters (in QSettings), otherwise show
           message with two buttons "Use DB from QSettings" and "Use the current connection".
        """
        # Check if current connection is valid and disable access if not
        inst = args[0]
        context = args[1]
        db_connections_in_conflict = list()
        invalid_db_connections = list()

        for db_source in context.get_db_sources():
            db = inst.conn_manager.get_db_connector_from_source(db_source)
            qsettings_db = inst.conn_manager.get_db_connection_from_qsettings(
                db_source)

            if db.equals(qsettings_db):
                res, code, msg = db.test_connection()
                if not res:
                    invalid_db_connections.append(db_source)
                    widget = inst.iface.messageBar().createMessage(
                        "Asistente LADM-COL",
                        QCoreApplication.translate(
                            "AsistenteLADMCOLPlugin",
                            "The {} DB connection is not valid. Details: {}").
                        format(Tr.tr_db_source(db_source), msg))
                    button = QPushButton(widget)
                    button.setText(
                        QCoreApplication.translate("AsistenteLADMCOLPlugin",
                                                   "Settings"))

                    settings_context = SettingsContext(db_source)
                    settings_context.title = QCoreApplication.translate(
                        "AsistenteLADMCOLPlugin",
                        "{} Connection Settings").format(
                            Tr.tr_db_source(db_source))
                    settings_context.tip = QCoreApplication.translate(
                        "AsistenteLADMCOLPlugin",
                        "Configure a valid DB connection for {} source."
                    ).format(Tr.tr_db_source(db_source))
                    settings_context.tab_pages_list = [
                        SETTINGS_CONNECTION_TAB_INDEX
                    ]
                    button.pressed.connect(
                        partial(inst.show_settings_clear_message_bar,
                                settings_context))

                    widget.layout().addWidget(button)
                    inst.iface.messageBar().pushWidget(widget, Qgis.Warning,
                                                       15)
                    inst.logger.warning(
                        __name__,
                        QCoreApplication.translate(
                            "AsistenteLADMCOLPlugin",
                            "A dialog/tool couldn't be opened/executed, connection to DB was not valid."
                        ))
                else:
                    # Update cache if there is none and source is Collected
                    if db_source == COLLECTED_DB_SOURCE:
                        if not inst.app.core.get_cached_layers(
                        ) and not inst.app.core.get_cached_relations():
                            inst.app.core.cache_layers_and_relations(
                                db, ladm_col_db=True, db_source=None)
            else:
                db_connections_in_conflict.append(db_source)
                msg = QCoreApplication.translate(
                    "AsistenteLADMCOLPlugin",
                    "Your current {} DB does not match with the one registered in QSettings. Which connection would you like to use?"
                ).format(Tr.tr_db_source(db_source))

                widget = inst.iface.messageBar().createMessage(
                    "Asistente LADM-COL", msg)
                btn_current_connection = QPushButton(widget)
                btn_current_connection.setText(
                    QCoreApplication.translate("AsistenteLADMCOLPlugin",
                                               "Use the current connection"))
                btn_current_connection.pressed.connect(
                    partial(inst.use_current_db_connection, db_source))

                btn_update_connection = QPushButton(widget)
                btn_update_connection.setText(
                    QCoreApplication.translate("AsistenteLADMCOLPlugin",
                                               "Use DB from QSettings"))
                btn_update_connection.pressed.connect(
                    partial(inst.update_db_connection_from_qsettings,
                            db_source))

                widget.layout().addWidget(btn_current_connection)
                widget.layout().addWidget(btn_update_connection)

                inst.iface.messageBar().pushWidget(widget, Qgis.Warning)
                inst.logger.warning(__name__, msg)

        if db_connections_in_conflict or invalid_db_connections:
            return  # If any db connection changed or it's invalid, we don't return the decorated function
        else:
            func_to_decorate(*args, **kwargs)