class ChangesPerParcelPanelWidget(QgsPanelWidget, WIDGET_UI): def __init__(self, parent, utils, parcel_number=None, collected_parcel_t_id=None): QgsPanelWidget.__init__(self, None) self.setupUi(self) self.parent = parent self.utils = utils self.logger = Logger() self.setDockMode(True) self.setPanelTitle( QCoreApplication.translate("ChangesPerParcelPanelWidget", "Change detection per parcel")) self._current_supplies_substring = "" self._current_substring = "" self.utils.add_layers() self.fill_combos() # Remove selection in plot layers self.utils._layers[self.utils._db.names.LC_PLOT_T].removeSelection() self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T].removeSelection() # Map tool before activate map swipe tool self.init_map_tool = self.utils.canvas.mapTool() self.active_map_tool_before_custom = None self.btn_identify_plot.setIcon( QIcon(":/Asistente-LADM-COL/resources/images/spatial_unit.png")) self.btn_identify_plot.clicked.connect(self.btn_plot_toggled) # Create maptool self.maptool_identify = QgsMapToolIdentifyFeature(self.utils.canvas) # Set connections self.btn_alphanumeric_query.clicked.connect(self.alphanumeric_query) self.chk_show_all_plots.toggled.connect(self.show_all_plots) self.cbo_parcel_fields.currentIndexChanged.connect( self.search_field_updated) self.panelAccepted.connect(self.initialize_tools_and_layers) self.tbl_changes_per_parcel.itemDoubleClicked.connect( self.call_party_panel) self.initialize_field_values_line_edit() self.initialize_tools_and_layers() if parcel_number is not None: # Do a search! self.txt_alphanumeric_query.setValue(parcel_number) if collected_parcel_t_id is not None: # Search data for a duplicated parcel_number, so, take the t_id into account! self.search_data(parcel_number=parcel_number, collected_parcel_t_id=collected_parcel_t_id) else: self.search_data(parcel_number=parcel_number) def btn_plot_toggled(self): self.clear_result_table() if self.btn_identify_plot.isChecked(): self.prepare_identify_plot() else: # The button was toggled and deactivated, go back to the previous tool self.utils.canvas.setMapTool(self.active_map_tool_before_custom) def clear_result_table(self): self.tbl_changes_per_parcel.clearContents() self.tbl_changes_per_parcel.setRowCount(0) def prepare_identify_plot(self): """ Custom Identify tool was activated, prepare everything for identifying plots """ self.active_map_tool_before_custom = self.utils.canvas.mapTool() self.btn_identify_plot.setChecked(True) self.utils.canvas.mapToolSet.connect(self.initialize_maptool) if self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T] is None: self.utils.add_layers() self.maptool_identify.setLayer(self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T]) cursor = QCursor() cursor.setShape(Qt.PointingHandCursor) self.maptool_identify.setCursor(cursor) self.utils.canvas.setMapTool(self.maptool_identify) try: self.maptool_identify.featureIdentified.disconnect() except TypeError as e: pass self.maptool_identify.featureIdentified.connect(self.get_info_by_plot) def get_info_by_plot(self, plot_feature): """ :param plot_feature: from supplies db """ plot_t_id = plot_feature[self.utils._supplies_db.names.T_ID_F] self.utils.canvas.flashFeatureIds(self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T], [plot_feature.id()], QColor(255, 0, 0, 255), QColor(255, 0, 0, 0), flashes=1, duration=500) if not self.isVisible(): self.show() self.spatial_query(plot_t_id) self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T].selectByIds( [plot_feature.id()]) def spatial_query(self, plot_id): if plot_id: parcel_number = self.utils.ladm_data.get_parcels_related_to_plots_supplies( self.utils._supplies_db, [plot_id], self.utils._supplies_db.names.GC_PARCEL_T_PARCEL_NUMBER_F) if parcel_number: # Delegate handling of duplicates to search_data() method self.search_data(parcel_number=parcel_number[0]) def call_party_panel(self, item): row = item.row() if self.tbl_changes_per_parcel.item(row, 0).text( ) == DICT_ALIAS_KEYS_CHANGE_DETECTION[DICT_KEY_PARTIES]: data = { SUPPLIES_DB_SOURCE: self.tbl_changes_per_parcel.item(row, 1).data(Qt.UserRole), COLLECTED_DB_SOURCE: self.tbl_changes_per_parcel.item(row, 2).data(Qt.UserRole) } self.parent.show_party_panel(data) def search_field_updated(self, index=None): self.initialize_field_values_line_edit() def initialize_field_values_line_edit(self): # We search for alphanumeric data in supplies data source self.txt_alphanumeric_query.setLayer(self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PARCEL_T]) search_option = self.cbo_parcel_fields.currentData() search_field_supplies = get_supplies_search_options( self.utils._supplies_db.names)[search_option] idx = self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PARCEL_T].fields().indexOf( search_field_supplies) self.txt_alphanumeric_query.setAttributeIndex(idx) def fill_combos(self): self.cbo_parcel_fields.clear() self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetChanges", "Parcel Number"), PARCEL_NUMBER_SEARCH_KEY) self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetChanges", "Previous Parcel Number"), PREVIOUS_PARCEL_NUMBER_SEARCH_KEY) self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetChanges", "Folio de Matrícula Inmobiliaria"), FMI_PARCEL_SEARCH_KEY) @_with_override_cursor def search_data(self, **kwargs): """ Get plot geometries associated with parcels, both collected and supplies, zoom to them, fill comparison table and activate map swipe tool. To fill the comparison table we build two search dicts, one for supplies (already given because the alphanumeric search is on supplies db source), and another one for collected. For the latter, we have 3 cases. We specify them below (inline). :param kwargs: key-value (field name-field value) to search in parcel tables, both collected and supplies Normally, keys are parcel_number, old_parcel_number or FMI, but if duplicates are found, an additional t_id disambiguates only for the collected source. In the supplies source we assume we will not find duplicates, if there are, we will choose the first record found an will not deal with letting the user choose one of the duplicates by hand (as we do for the collected source). """ self.chk_show_all_plots.setEnabled(False) self.chk_show_all_plots.setChecked(True) self.initialize_tools_and_layers() # Reset any filter on layers plots_supplies = list() plots_collected = list() self.clear_result_table() search_option = self.cbo_parcel_fields.currentData() search_field_supplies = get_supplies_search_options( self.utils._supplies_db.names)[search_option] search_field_collected = get_collected_search_options( self.utils._db.names)[search_option] search_value = list(kwargs.values())[0] # Build search criterion for both supplies and collected search_criterion_supplies = {search_field_supplies: search_value} # Get supplies parcel's t_id and get related plot(s) expression_supplies = QgsExpression("{}='{}'".format( search_field_supplies, search_value)) request = QgsFeatureRequest(expression_supplies) field_idx = self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PARCEL_T].fields().indexFromName( self.utils._supplies_db.names.T_ID_F) request.setFlags(QgsFeatureRequest.NoGeometry) request.setSubsetOfAttributes([field_idx ]) # Note: this adds a new flag supplies_parcels = [ feature for feature in self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PARCEL_T].getFeatures(request) ] if len(supplies_parcels) > 1: # We do not expect duplicates in the supplies source! pass # We'll choose the first one anyways elif len(supplies_parcels) == 0: self.logger.info( __name__, "No supplies parcel found! Search: {}={}".format( search_field_supplies, search_value)) supplies_plot_t_ids = [] if supplies_parcels: supplies_plot_t_ids = self.utils.ladm_data.get_plots_related_to_parcels_supplies( self.utils._supplies_db, [supplies_parcels[0][self.utils._supplies_db.names.T_ID_F]], self.utils._supplies_db.names.T_ID_F, self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T]) if supplies_plot_t_ids: self._current_supplies_substring = "\"{}\" IN ('{}')".format( self.utils._supplies_db.names.T_ID_F, "','".join([str(t_id) for t_id in supplies_plot_t_ids])) plots_supplies = self.utils.ladm_data.get_features_from_t_ids( self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T], self.utils._supplies_db.names.T_ID_F, supplies_plot_t_ids, True) # Now get COLLECTED parcel's t_id to build the search dict for collected collected_parcel_t_id = None if 'collected_parcel_t_id' in kwargs: # This is the case when this panel is called and we already know the parcel number is duplicated collected_parcel_t_id = kwargs['collected_parcel_t_id'] search_criterion_collected = { self.utils._db.names.T_ID_F: collected_parcel_t_id } # As there are duplicates, we need to use t_ids else: # This is the case when: # + Either this panel was called and we know the parcel number is not duplicated, or # + This panel was shown without knowing about duplicates (e.g., individual parcel search) and we still # need to discover whether we have duplicates for this search criterion search_criterion_collected = {search_field_collected: search_value} expression_collected = QgsExpression("{}='{}'".format( search_field_collected, search_value)) request = QgsFeatureRequest(expression_collected) request.setFlags(QgsFeatureRequest.NoGeometry) request.setSubsetOfAttributes( [self.utils._db.names.T_ID_F], self.utils._layers[self.utils._db.names.LC_PARCEL_T].fields( )) # Note this adds a new flag collected_parcels = self.utils._layers[ self.utils._db.names.LC_PARCEL_T].getFeatures(request) collected_parcels_t_ids = [ feature[self.utils._db.names.T_ID_F] for feature in collected_parcels ] if collected_parcels_t_ids: collected_parcel_t_id = collected_parcels_t_ids[0] if len(collected_parcels_t_ids ) > 1: # Duplicates in collected source after a search QApplication.restoreOverrideCursor( ) # Make sure cursor is not waiting (it is if on an identify) QCoreApplication.processEvents() dlg_select_parcel = SelectDuplicateParcelDialog( self.utils, collected_parcels_t_ids, self.parent) dlg_select_parcel.exec_() if dlg_select_parcel.parcel_t_id: # User selected one of the duplicated parcels collected_parcel_t_id = dlg_select_parcel.parcel_t_id search_criterion_collected = { self.utils._db.names.T_ID_F: collected_parcel_t_id } else: return # User just cancelled the dialog, there is nothing more to do self.fill_table(search_criterion_supplies, search_criterion_collected) # Now get related plot(s) for both collected and supplies, if collected_parcel_t_id is not None: plot_t_ids = self.utils.ladm_data.get_plots_related_to_parcels( self.utils._db, [collected_parcel_t_id], self.utils._db.names.T_ID_F, plot_layer=self.utils._layers[self.utils._db.names.LC_PLOT_T], uebaunit_table=self.utils._layers[ self.utils._db.names.COL_UE_BAUNIT_T]) if plot_t_ids: self._current_substring = "{} IN ('{}')".format( self.utils._db.names.T_ID_F, "','".join([str(t_id) for t_id in plot_t_ids])) plots_collected = self.utils.ladm_data.get_features_from_t_ids( self.utils._layers[self.utils._db.names.LC_PLOT_T], self.utils._db.names.T_ID_F, plot_t_ids, True) # Zoom to combined extent plot_features = plots_supplies + plots_collected # Feature list plots_extent = QgsRectangle() for plot in plot_features: plots_extent.combineExtentWith(plot.geometry().boundingBox()) if not plots_extent.isEmpty(): self.utils.iface.mapCanvas().zoomToFeatureExtent(plots_extent) if plots_supplies and plots_collected: # Otherwise the map swipe tool doesn't add any value :) # Activate Swipe Tool self.utils.app.gui.activate_layer(self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T]) self.parent.activate_map_swipe_tool() # Send a custom mouse move on the map to make the map swipe tool's limit appear on the canvas coord_x = plots_extent.xMaximum() - (plots_extent.xMaximum( ) - plots_extent.xMinimum()) / 9 # 90% coord_y = plots_extent.yMaximum() - (plots_extent.yMaximum( ) - plots_extent.yMinimum()) / 2 # 50% coord_transform = self.utils.iface.mapCanvas( ).getCoordinateTransform() map_point = coord_transform.transform(coord_x, coord_y) widget_point = map_point.toQPointF().toPoint() global_point = self.utils.canvas.mapToGlobal(widget_point) self.utils.canvas.mousePressEvent( QMouseEvent(QEvent.MouseButtonPress, global_point, Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)) self.utils.canvas.mouseMoveEvent( QMouseEvent(QEvent.MouseMove, widget_point + QPoint(1, 0), Qt.NoButton, Qt.LeftButton, Qt.NoModifier)) self.utils.canvas.mouseReleaseEvent( QMouseEvent(QEvent.MouseButtonRelease, widget_point + QPoint(1, 0), Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)) # Once the query is done, activate the checkbox to alternate all plots/only selected plot self.chk_show_all_plots.setEnabled(True) def fill_table(self, search_criterion_supplies, search_criterion_collected): """ Shouldn't handle 'inverse' mode as we won't switch table columns at runtime. :param search_criterion_supplies: key-value pair to build an expression to search data in the supplies source :param search_criterion_collected: key-value pair to build an expression to search data in the collected source :return: """ plural = LayerConfig.get_dict_plural(self.utils._db.names) dict_collected_parcels = self.utils.ladm_data.get_parcel_data_to_compare_changes( self.utils._db, search_criterion_collected) # Custom layer modifiers layer_modifiers = { LayerConfig.PREFIX_LAYER_MODIFIERS: LayerConfig.SUPPLIES_DB_PREFIX, LayerConfig.SUFFIX_LAYER_MODIFIERS: LayerConfig.SUPPLIES_DB_SUFFIX, LayerConfig.STYLE_GROUP_LAYER_MODIFIERS: Symbology().get_style_group_layer_modifiers( self.utils._supplies_db.names) } dict_supplies_parcels = self.utils.ladm_data.get_parcel_data_to_compare_changes_supplies( self.utils._supplies_db, search_criterion_supplies, layer_modifiers=layer_modifiers) # Before filling the table we make sure we get one and only one parcel attrs dict collected_attrs = dict() if dict_collected_parcels: collected_parcel_number = list(dict_collected_parcels.keys())[0] collected_attrs = dict_collected_parcels[collected_parcel_number][ 0] del collected_attrs[ self.utils._db.names. T_ID_F] # Remove this line if self.utils._db.names.T_ID_F is somehow needed supplies_attrs = dict() if dict_supplies_parcels: supplies_parcel_number = list(dict_supplies_parcels.keys())[0] supplies_attrs = dict_supplies_parcels[supplies_parcel_number][0] del supplies_attrs[ self.utils._supplies_db.names. T_ID_F] # Remove this line if self.utils._supplies_db.names,T_ID_F is somehow needed number_of_rows = len(collected_attrs) or len(supplies_attrs) self.tbl_changes_per_parcel.setRowCount( number_of_rows) # t_id shouldn't be counted self.tbl_changes_per_parcel.setSortingEnabled(False) field_names = list( collected_attrs.keys()) if collected_attrs else list( supplies_attrs.keys()) if PLOT_GEOMETRY_KEY in field_names: field_names.remove( PLOT_GEOMETRY_KEY) # We'll handle plot geometry separately for row, field_name in enumerate(field_names): supplies_value = supplies_attrs[ field_name] if field_name in supplies_attrs else NULL collected_value = collected_attrs[ field_name] if field_name in collected_attrs else NULL field_alias = DICT_ALIAS_KEYS_CHANGE_DETECTION[ field_name] if field_name in DICT_ALIAS_KEYS_CHANGE_DETECTION else field_name self.fill_row(field_alias, supplies_value, collected_value, row, plural) if number_of_rows: # At least one row in the table? self.fill_geometry_row( PLOT_GEOMETRY_KEY, supplies_attrs[PLOT_GEOMETRY_KEY] if PLOT_GEOMETRY_KEY in supplies_attrs else QgsGeometry(), collected_attrs[PLOT_GEOMETRY_KEY] if PLOT_GEOMETRY_KEY in collected_attrs else QgsGeometry(), number_of_rows - 1) self.tbl_changes_per_parcel.setSortingEnabled(True) def fill_row(self, field_name, supplies_value, collected_value, row, plural): item = QTableWidgetItem(field_name) # item.setData(Qt.UserRole, parcel_attrs[self.names.T_ID_F]) self.tbl_changes_per_parcel.setItem(row, 0, item) if field_name == DICT_ALIAS_KEYS_CHANGE_DETECTION[DICT_KEY_PARTIES]: item = self.fill_party_item(supplies_value) self.tbl_changes_per_parcel.setItem(row, 1, item) item = self.fill_party_item(collected_value) self.tbl_changes_per_parcel.setItem(row, 2, item) self.tbl_changes_per_parcel.setItem(row, 3, QTableWidgetItem()) self.tbl_changes_per_parcel.item(row, 3).setBackground( Qt.green if supplies_value == collected_value else Qt.red) else: item = QTableWidgetItem( str(supplies_value) if supplies_value != NULL else '') #item.setData(Qt.UserRole, parcel_attrs[self.names.T_ID_F]) self.tbl_changes_per_parcel.setItem(row, 1, item) item = QTableWidgetItem( str(collected_value) if collected_value != NULL else '') # item.setData(Qt.UserRole, parcel_attrs[self.names.T_ID_F]) self.tbl_changes_per_parcel.setItem(row, 2, item) self.tbl_changes_per_parcel.setItem(row, 3, QTableWidgetItem()) self.tbl_changes_per_parcel.item(row, 3).setBackground( Qt.green if supplies_value == collected_value else Qt.red) def fill_party_item(self, value): # Party's info comes in a list or a list of lists if it's a group party display_value = '' if value != NULL: if type(value) is list and value: display_value = "{} {}".format( len(value), QCoreApplication.translate("DockWidgetChanges", "parties") if len(value) > 1 else QCoreApplication.translate( "DockWidgetChanges", "party")) #else: # display_value = QCoreApplication.translate("DockWidgetChanges", "0 parties") item = QTableWidgetItem(display_value) item.setData(Qt.UserRole, value) return item def fill_geometry_row(self, field_name, supplies_geom, collected_geom, row): self.tbl_changes_per_parcel.setItem( row, 0, QTableWidgetItem( QCoreApplication.translate("DockWidgetChanges", "Geometry"))) self.tbl_changes_per_parcel.setItem( row, 1, QTableWidgetItem(self.get_geometry_type_name(supplies_geom))) self.tbl_changes_per_parcel.setItem( row, 2, QTableWidgetItem(self.get_geometry_type_name(collected_geom))) self.tbl_changes_per_parcel.setItem(row, 3, QTableWidgetItem()) self.tbl_changes_per_parcel.item(row, 3).setBackground( Qt.green if self.utils.compare_features_geometries( collected_geom, supplies_geom) else Qt.red) @staticmethod def get_geometry_type_name(geometry): if geometry is None: return QCoreApplication.translate("DockWidgetChanges", "No associated plot") elif geometry.type() == QgsWkbTypes.UnknownGeometry: return '' elif geometry.type() == QgsWkbTypes.PolygonGeometry: return QCoreApplication.translate("DockWidgetChanges", "Polygon") else: return "Type: {}".format(geometry.type()) def alphanumeric_query(self): """ Alphanumeric query (On supplies db) """ option = self.cbo_parcel_fields.currentData() query = self.txt_alphanumeric_query.value() if query: if option == FMI_PARCEL_SEARCH_KEY: self.search_data(parcel_fmi=query) elif option == PARCEL_NUMBER_SEARCH_KEY: self.search_data(parcel_number=query) else: # previous_parcel_number self.search_data(previous_parcel_number=query) else: self.utils.iface.messageBar().pushMessage( "Asistente LADM-COL", QCoreApplication.translate("DockWidgetChanges", "First enter a query")) def show_all_plots(self, state): try: self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T].setSubsetString( self._current_supplies_substring if not state else "") except RuntimeError: # If the layer was previously removed pass try: self.utils._layers[self.utils._db.names.LC_PLOT_T].setSubsetString( self._current_substring if not state else "") except RuntimeError: # If the layer was previously removed pass def initialize_tools_and_layers(self, panel=None): self.parent.deactivate_map_swipe_tool() self.show_all_plots(True) def initialize_maptool(self, new_tool, old_tool): if self.maptool_identify == old_tool: # custom identify was deactivated try: self.utils.canvas.mapToolSet.disconnect( self.initialize_maptool) except TypeError as e: pass self.btn_identify_plot.setChecked(False) else: # custom identify was activated pass def close_panel(self): self.show_all_plots( True ) # Remove filter in plots layers if it was activate and panel is closed # custom identify was deactivated try: self.utils.canvas.mapToolSet.disconnect(self.initialize_maptool) except TypeError as e: pass self.utils.canvas.setMapTool(self.init_map_tool)
class TransfoPtToPlot(QDialog, gui_dlg_transfo_pttoplot): def __init__(self, canvas, project, l_vertex, l_edge, parent=None): super(TransfoPtToPlot, self).__init__(parent) self.setupUi(self) self.canvas = canvas self.project = project self.l_edge = l_edge self.l_vertex = l_vertex self.sel_nw_vtx = None self.resize_dlg = ResizeDlg(self, "dlg_transfo_pt_to_plots") self.resize_params = self.resize_dlg.load_dlgresize() self.resize_on = self.resize_params["dlg_transfo_pt_to_plots"] self.buttValid.clicked.connect(self.close) self.buttResize.clicked.connect(self.resize_dlg.dlg_ch_resize) self.selrfuvtxnearButt.clicked.connect(self.sel_nwvtxnear_rfu) self.nearvtxvalButt.clicked.connect(self.nwvtx_valid) self.selnwvxtButt.clicked.connect(self.sel_nwvtxfar) self.selrfuvtxfarButt.clicked.connect(self.sel_rfuvtxfar) self.nearvtxTbv.clicked.connect(self.tbv_sel) # Delete Widget on close event self.setAttribute(Qt.WA_DeleteOnClose) # Zoom to 2 new + RFU vertices if a line is selected in the tableview def tbv_sel(self): # Find the selected cell (considering only the first selected cell) idx = self.nearvtxTbv.selectedIndexes()[0].row() # Find the new vertex feature and the near RFU vertex feature self.sel_nw_vtx = self.nr_feats[idx] id_rfu_vtx = self.nr_feats[idx]["point_rfu_proche"] rfu_vtx = feats_by_cond(self.l_vertex, r"@id_noeud", id_rfu_vtx)[0] # Zoom to the 2 features self.canvas.zoomToFeatureIds(self.l_vertex, [self.sel_nw_vtx.id(), rfu_vtx.id()]) # Let the user select the new vertex to transform into a plot def sel_nwvtxfar(self): # Selection in the canvas self.hide() self.identify_nwvtxfar_vtx = QgsMapToolIdentifyFeature(self.canvas, self.l_vertex) self.identify_nwvtxfar_vtx.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_nwvtxfar_vtx.featureIdentified.connect(self.far_nwvtx_identified) self.canvas.setMapTool(self.identify_nwvtxfar_vtx) def far_nwvtx_identified(self, feat): self.l_vertex.selectByIds([feat.id()]) # Check if the point selected is a new vertex if not feat[r"@id_noeud"]: self.sel_nw_vtx = feat self.canvas.unsetMapTool(self.identify_nwvtxfar_vtx) self.dlg_show() else: QMessageBox.warning(self, tr_vtxplt_notnwvtx_msg[0], tr_vtxplt_notnwvtx_msg[1]) # Let the user select the RFU vertex to use with the far new vertex def sel_rfuvtxfar(self): # Selection in the canvas if self.sel_nw_vtx: self.hide() self.identify_rfuvtxfar_vtx = QgsMapToolIdentifyFeature(self.canvas, self.l_vertex) self.identify_rfuvtxfar_vtx.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_rfuvtxfar_vtx.featureIdentified.connect(partial(self.rfu_vtx_identified, "far")) self.canvas.setMapTool(self.identify_rfuvtxfar_vtx) # Message if no line selected in the tableview else: QMessageBox.warning(self, tr_vtxplt_sel_nonwvtxsel_msg[0], tr_vtxplt_sel_nonwvtxsel_msg[1]) # Let the user select the RFU vertex near the new vertex def sel_nwvtxnear_rfu(self): # Selection in the canvas if self.sel_nw_vtx: self.hide() self.identify_rfu_vtx = QgsMapToolIdentifyFeature(self.canvas, self.l_vertex) self.identify_rfu_vtx.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_rfu_vtx.featureIdentified.connect(partial(self.rfu_vtx_identified, "near")) self.canvas.setMapTool(self.identify_rfu_vtx) # Message if no line selected in the tablview else: QMessageBox.warning(self, tr_vtxplt_sel_nolinesel_msg[0], tr_vtxplt_sel_nolinesel_msg[1]) def rfu_vtx_identified(self, vtx_type, feat): self.vtx_type = vtx_type self.l_vertex.selectByIds([feat.id()]) if self.vtx_type == "near": self.canvas.unsetMapTool(self.identify_rfu_vtx) else: self.canvas.unsetMapTool(self.identify_rfuvtxfar_vtx) # Check if the point selected is a RFU vertex if feat[r"@id_noeud"]: id_node = feat[r"@id_noeud"] # Tolerance in cm tol = feat[r"som_tolerance"]*100 nw_coord_e = self.sel_nw_vtx["som_coord_est"] nw_coord_n = self.sel_nw_vtx["som_coord_nord"] nw_rep_plane = self.sel_nw_vtx["som_representation_plane"] nw_pt_cc = QgsPointXY(self.sel_nw_vtx["som_coord_est"], self.sel_nw_vtx["som_coord_nord"]) rfu_pt_cc = QgsPointXY(feat["som_coord_est"], feat["som_coord_nord"]) # Distance between the 2 points in cm dist_vtx = dist_2_pts(nw_pt_cc, rfu_pt_cc)*100 if dist_vtx < tol: self.vtx_type = "near" # Check if the 2 points have the same som_representation_plane # Otherwise, cancel the process if nw_rep_plane == feat["som_representation_plane"]: if self.vtx_type == "near": tl_msg = tr_vtxplt_confirm_msg[0] txt_msg = tr_vtxplt_confirm_msg[1].format(nw_coord_e, nw_coord_n, id_node) else: tl_msg = tr_vtxplt_attest_msg[0] txt_msg = tr_vtxplt_attest_msg[1].format(nw_coord_e, nw_coord_n, id_node, dist_vtx, tol) confirm = QMessageBox.question( self, tl_msg, txt_msg, QMessageBox.Yes | QMessageBox.No) if confirm == QMessageBox.Yes: nw_vals = {} for att in tr_toplot_atts: id_att = self.l_vertex.fields().indexFromName(att) nw_vals[id_att] = self.sel_nw_vtx[att] # Change the atteste_qualite value if self.vtx_type == "far": id_att = self.l_vertex.fields().indexFromName("attestation_qualite") nw_vals[id_att] = "true" self.l_vertex.changeAttributeValues(feat.id(), nw_vals) self.l_vertex.deleteFeature(self.sel_nw_vtx.id()) self.tr_edges(self.sel_nw_vtx.geometry(), feat.geometry()) self.canvas.refresh() QMessageBox.information( self, tr_vtxplot_transfok_msg[0], tr_vtxplot_transfok_msg[1].format(nw_coord_e, nw_coord_n, id_node)) # Process canceled by the user else: QMessageBox.information(self, tr_vtxplt_canceld_msg[0], tr_vtxplt_canceld_msg[1]) # Case of no same som_representation_plane else: QMessageBox.warning(self, tr_vtxplot_nosamerp_msg[0], tr_vtxplot_nosamerp_msg[1]) self.nearvtxTbv.clearSelection() self.sel_nw_vtx = None # Deselect point self.l_vertex.selectByIds([]) self.dlg_show() else: QMessageBox.warning(self, tr_vtxplt_notrfuvtx_msg[0], tr_vtxplt_notrfuvtx_msg[1]) if self.vtx_type == "near": self.sel_nwvtxnear_rfu() else: self.sel_rfuvtxfar() # Move edges if they are linked to a new vertex transformed into plot def tr_edges(self, old_geom, nw_geom): # Transformations to obtain the WGS84 or the CC coordinates coords_tr_wgs, coords_tr_cc = crs_trans_params(self.canvas, self.project) old_geom_pt = old_geom.asPoint() nw_geom_pt = nw_geom.asPoint() old_geom_cc = coords_tr_cc.transform(old_geom_pt) # Process only new edges nw_edges = feats_by_cond(self.l_edge, "@id_arc", NULL) if len(nw_edges) > 0: for edge_ft in nw_edges: ch_geom = False edge_ft_line = edge_ft.geometry().asPolyline() start_pt = edge_ft_line[0] end_pt = edge_ft_line[-1] # Comparison done on cc coordinates start_pt_cc = coords_tr_cc.transform(start_pt) end_pt_cc = coords_tr_cc.transform(end_pt) # Case of start point to move if check_identical_pts(old_geom_cc, start_pt_cc, 2): self.l_edge.moveVertex(nw_geom_pt.x(), nw_geom_pt.y(), edge_ft.id(), 0) nw_line_g = QgsGeometry.fromPolylineXY([nw_geom_pt, end_pt]) ch_geom = True # Case of end point to move if check_identical_pts(old_geom_cc, end_pt_cc, 2): self.l_edge.moveVertex(nw_geom_pt.x(), nw_geom_pt.y(), edge_ft.id(), 1) nw_line_g = QgsGeometry.fromPolylineXY([start_pt, nw_geom_pt]) ch_geom = True # Check if new line is the same as an existing edge_ft # In this case, delete the new line if ch_geom: for old_edge_ft in self.l_edge.getFeatures(): if old_edge_ft.id() != edge_ft.id() and \ check_identical_lines(old_edge_ft.geometry().asPolyline(), nw_line_g.asPolyline(), 12): self.l_edge.deleteFeature(edge_ft.id()) # Let the user valid the new vertex def nwvtx_valid(self): # Reset the point_rfu_proche field if self.sel_nw_vtx: self.l_vertex.changeAttributeValue(self.sel_nw_vtx.id(), 10, NULL) # self.l_vertex.commitChanges() self.canvas.refresh() QMessageBox.information(self, tr_vtxplt_valid_msg[0], tr_vtxplt_valid_msg[1].format(self.sel_nw_vtx["som_coord_est"], self.sel_nw_vtx["som_coord_nord"])) self.nearvtxTbv.clearSelection() self.sel_nw_vtx = None self.hide() self.dlg_show() # Message if no line selected in the tablview else: QMessageBox.warning(self, tr_vtxplt_nolinesel_msg[0], tr_vtxplt_nolinesel_msg[1]) # Launch the dlg appearence def dlg_show(self): self.nr_feats = [] # Create the tableview self.tr_vtxtbl_data = [] tr_vtxtbl_hd = [] # Build the header for fld_name in tr_vtx_atts: tr_vtxtbl_hd.append(fld_name) # Build the contents nb_rows = 0 for obj in self.l_vertex.getFeatures(): if obj['point_rfu_proche']: tr_vtxtbl_row = [] for fld_name in tr_vtx_atts: tr_vtxtbl_row.append(str(obj[fld_name])) self.tr_vtxtbl_data.append(tr_vtxtbl_row) self.nr_feats.append(obj) nb_rows += 1 if nb_rows != 0: tr_vtxtbl_model=MyTableModel(self, self.tr_vtxtbl_data, tr_vtxtbl_hd) # Populate data in the tableview self.nearvtxTbv.setModel(tr_vtxtbl_model) self.height_tbv = 0 self.width_tbv = 0 # Set column width to fit contents self.nearvtxTbv.resizeColumnsToContents() # Increase a little bit the width of the columns for id_col, val_col in enumerate(tr_vtxtbl_hd): nw_size = self.nearvtxTbv.columnWidth(id_col) + 5 self.nearvtxTbv.setColumnWidth(id_col, nw_size) self.width_tbv += nw_size # Set row height self.nearvtxTbv.resizeRowsToContents() self.height_tbv = (self.nearvtxTbv.rowHeight(0)) * (nb_rows+1) self.width_tbv += 45 self.height_tbv += 330 self.resize_dlg.wtbv = self.width_tbv self.resize_dlg.htbv = self.height_tbv # Hide vertical header vh = self.nearvtxTbv.verticalHeader() vh.setVisible(False) else: self.nearvtxGp.hide() self.width_tbv = dlg_transfo_pt_to_plots_sw self.height_tbv = 176 self.resize_dlg.wtbv = self.width_tbv self.resize_dlg.htbv = self.height_tbv if self.resize_on: self.resize_dlg.dlg_auto_resize() self.show() def to_close(self): self.close()
class EdgeCreator(QDockWidget, gui_dckwdgt_edge_creator): def __init__(self, canvas, l_vertex, l_edge, user=None, auth_creator=[], parent=None): super(EdgeCreator, self).__init__(parent) self.setupUi(self) # Delete Widget on close event.. self.setAttribute(Qt.WA_DeleteOnClose) self.save = False self.canvas = canvas self.l_edge = l_edge self.l_vertex = l_vertex self.user = user self.auth_creator = auth_creator self.vertices = self.l_vertex.getFeatures() self.vtx_start = None self.vtx_end = None self.selected_vertices = [None, None] self.edge = None for i, vertex in enumerate(self.vertices): self.startVertexComboBox.insertItem(i, str(vertex.id())) self.startVertexComboBox.setItemData(i, vertex, 32) self.startVertexComboBox.setCurrentIndex(-1) self.endVertexComboBox.insertItem(i, str(vertex.id())) self.endVertexComboBox.setItemData(i, vertex, 32) self.endVertexComboBox.setCurrentIndex(-1) # Attribute: `som_createur` for i, e in enumerate(self.auth_creator): self.creatorComboBox.addItem(u"%s (%s)" % (e[1], e[0])) if self.user == e[0]: self.creatorComboBox.setCurrentIndex(i) self.startVertextoolButton.clicked.connect( self.select_start_vertex_on_canvas) self.endVertextoolButton.clicked.connect( self.select_end_vertex_on_canvas) self.startVertexComboBox.highlighted.connect(self.on_vtx_start_pressed) self.endVertexComboBox.highlighted.connect(self.on_vtx_end_pressed) self.startVertexComboBox.currentIndexChanged.connect( self.on_vtx_start_pressed) self.endVertexComboBox.currentIndexChanged.connect( self.on_vtx_end_pressed) self.startVertexComboBox.highlighted.connect(self.create_edge) self.endVertexComboBox.highlighted.connect(self.create_edge) self.startVertexComboBox.currentIndexChanged.connect(self.create_edge) self.endVertexComboBox.currentIndexChanged.connect(self.create_edge) self.buttonBox.accepted.connect(self.on_accepted) self.buttonBox.rejected.connect(self.on_rejected) self.buttonBox.button(QDialogButtonBox.Reset).clicked.connect( self.on_reset) def closeEvent(self, event): if not self.save: self.on_rejected() def select_start_vertex_on_canvas(self): self.identify_start_vertex = QgsMapToolIdentifyFeature( self.canvas, self.l_vertex) self.identify_start_vertex.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_start_vertex.featureIdentified.connect( self.on_start_vertex_identified) self.canvas.setMapTool(self.identify_start_vertex) def select_end_vertex_on_canvas(self): self.identify_end_vertex = QgsMapToolIdentifyFeature( self.canvas, self.l_vertex) self.identify_end_vertex.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_end_vertex.featureIdentified.connect( self.on_end_vertex_identified) self.canvas.setMapTool(self.identify_end_vertex) def on_start_vertex_identified(self, feature): cb = self.startVertexComboBox items = [cb.itemText(i) for i in range(cb.count())] for i, e in enumerate(items): if int(feature.id()) == int(e): cb.setCurrentIndex(i) def on_end_vertex_identified(self, feature): cb = self.endVertexComboBox items = [cb.itemText(i) for i in range(cb.count())] for i, e in enumerate(items): if int(feature.id()) == int(e): cb.setCurrentIndex(i) def on_vtx_start_pressed(self, idx): self.vtx_start = self.startVertexComboBox.itemData(idx, 32) self.select_vertices(self.vtx_start, 0) self.endVertexComboBox.setEnabled(True) self.endVertextoolButton.setEnabled(True) def on_vtx_end_pressed(self, idx): self.vtx_end = self.endVertexComboBox.itemData(idx, 32) self.select_vertices(self.vtx_end, 1) self.creatorComboBox.setEnabled(True) def select_vertices(self, feature, i): if feature: self.selected_vertices[i] = feature.id() else: self.selected_vertices[i] = None self.l_vertex.setSelectedFeatures(self.selected_vertices) def unselect_vertices(self): self.l_vertex.setSelectedFeatures([]) def create_edge(self): # If edge already exists, delete it.. if self.edge: self.l_edge.deleteFeature(self.edge.id()) # Two vertices are needed.. if not self.vtx_start or not self.vtx_end: return self.canvas.refresh() # Two DIFFERENT vertices.. if self.vtx_start == self.vtx_end: return self.canvas.refresh() # Create line geometry.. line = QgsGeometry.fromPolyline([ self.vtx_start.geometry().asPoint(), self.vtx_end.geometry().asPoint() ]) # Create the feature.. self.edge = QgsFeature() self.edge.setGeometry(line) self.edge.setFields(self.l_edge.pendingFields()) self.edge.setAttributes( [QPyNullVariant(int), QPyNullVariant(int), QPyNullVariant(int)]) # Add feature to layer.. self.l_edge.addFeature(self.edge) self.canvas.refresh() def on_accepted(self): if not self.edge: return False self.lim_ge_createur = self.auth_creator[ self.creatorComboBox.currentIndex()][0] self.edge.setAttributes( [QPyNullVariant(int), QPyNullVariant(int), self.lim_ge_createur]) self.l_edge.updateFeature(self.edge) self.canvas.refresh() self.save = True self.close() def on_rejected(self): # Do not save the feature.. if self.edge: self.l_edge.deleteFeature(self.edge.id()) self.unselect_vertices() self.canvas.refresh() self.close() def on_reset(self): self.startVertexComboBox.setCurrentIndex(0) # self.startVertexComboBox.setEnabled(True) # self.startVertexLabel.setEnabled(True) self.endVertexComboBox.setCurrentIndex(0) self.endVertexComboBox.setEnabled(False) self.endVertexLabel.setEnabled(False) self.endVertextoolButton.setEnabled(False) for i, e in enumerate(self.auth_creator): if self.user == e[0]: self.creatorComboBox.setCurrentIndex(i) self.creatorComboBox.setEnabled(False) self.creatorLabel.setEnabled(False) self.unselect_vertices() self.canvas.refresh()
class DockWidgetQueries(QgsDockWidget, DOCKWIDGET_UI): zoom_to_features_requested = pyqtSignal(QgsVectorLayer, list, dict, int) # layer, ids, t_ids, duration def __init__(self, iface, db, qgis_utils, ladm_data, parent=None): super(DockWidgetQueries, self).__init__(None) self.setupUi(self) self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.iface = iface self._db = db self.qgis_utils = qgis_utils self.ladm_data = ladm_data self.logger = Logger() self.canvas = iface.mapCanvas() self.active_map_tool_before_custom = None self.names = self._db.names self.clipboard = QApplication.clipboard() # Required layers self.restart_dict_of_layers() self._identify_tool = None self.add_layers() self.fill_combos() self.btn_identify_plot.setIcon( QIcon(":/Asistente-LADM_COL/resources/images/spatial_unit.png")) # Set connections self.btn_alphanumeric_query.clicked.connect(self.alphanumeric_query) self.cbo_parcel_fields.currentIndexChanged.connect( self.search_field_updated) self.btn_identify_plot.clicked.connect(self.btn_plot_toggled) # Context menu self._set_context_menus() # Create maptool self.maptool_identify = QgsMapToolIdentifyFeature(self.canvas) self.initialize_field_values_line_edit() def search_field_updated(self, index=None): self.initialize_field_values_line_edit() def initialize_field_values_line_edit(self): self.txt_alphanumeric_query.setLayer( self._layers[self.names.OP_PARCEL_T][LAYER]) idx = self._layers[self.names.OP_PARCEL_T][LAYER].fields().indexOf( self.cbo_parcel_fields.currentData()) self.txt_alphanumeric_query.setAttributeIndex(idx) def _set_context_menus(self): self.tree_view_basic.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_basic.customContextMenuRequested.connect( self.show_context_menu) self.tree_view_legal.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_legal.customContextMenuRequested.connect( self.show_context_menu) self.tree_view_property_record_card.setContextMenuPolicy( Qt.CustomContextMenu) self.tree_view_property_record_card.customContextMenuRequested.connect( self.show_context_menu) self.tree_view_physical.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_physical.customContextMenuRequested.connect( self.show_context_menu) self.tree_view_economic.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_economic.customContextMenuRequested.connect( self.show_context_menu) def restart_dict_of_layers(self): self._layers = { self.names.OP_PLOT_T: { 'name': self.names.OP_PLOT_T, 'geometry': QgsWkbTypes.PolygonGeometry, LAYER: None }, self.names.OP_PARCEL_T: { 'name': self.names.OP_PARCEL_T, 'geometry': None, LAYER: None }, self.names.COL_UE_BAUNIT_T: { 'name': self.names.COL_UE_BAUNIT_T, 'geometry': None, LAYER: None } } def add_layers(self): self.qgis_utils.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 try: self._layers[self.names.OP_PLOT_T][LAYER].willBeDeleted.disconnect( self.layer_removed) except TypeError as e: pass self._layers[self.names.OP_PLOT_T][LAYER].willBeDeleted.connect( self.layer_removed) # Layer was found, listen to its removal so that we can update the variable properly try: self._layers[ self.names.OP_PARCEL_T][LAYER].willBeDeleted.disconnect( self.parcel_layer_removed) except TypeError as e: pass self._layers[self.names.OP_PARCEL_T][LAYER].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.names.COL_UE_BAUNIT_T][LAYER].willBeDeleted.disconnect( self.uebaunit_table_removed) except TypeError as e: pass self._layers[self.names.COL_UE_BAUNIT_T][LAYER].willBeDeleted.connect( self.uebaunit_table_removed) def initialize_tool(self): self._layers[self.names.OP_PLOT_T][LAYER] = None self.initialize_tools(new_tool=None, old_tool=self.maptool_identify) self.btn_plot_toggled() def update_db_connection(self, db, ladm_col_db, db_source): self._db = db self.initialize_tool() if not ladm_col_db: self.setVisible(False) def layer_removed(self): # The required layer was removed, deactivate custom tool self.initialize_tool() def parcel_layer_removed(self): self._layers[self.names.OP_PARCEL_T][LAYER] = None def uebaunit_table_removed(self): self._layers[self.names.COL_UE_BAUNIT_T][LAYER] = None def fill_combos(self): self.cbo_parcel_fields.clear() self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetQueries", "Parcel Number"), self.names.OP_PARCEL_T_PARCEL_NUMBER_F) self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetQueries", "Previous Parcel Number"), self.names.OP_PARCEL_T_PREVIOUS_PARCEL_NUMBER_F) self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetQueries", "Folio de Matrícula Inmobiliaria"), self.names.OP_PARCEL_T_FMI_F) def initialize_tools(self, new_tool, old_tool): if self.maptool_identify == old_tool: # custom identify was deactivated try: self.canvas.mapToolSet.disconnect(self.initialize_tools) except TypeError as e: pass self.btn_identify_plot.setChecked(False) else: # custom identify was activated pass def btn_plot_toggled(self): if self.btn_identify_plot.isChecked(): self.prepare_identify_plot() else: # The button was toggled and deactivated, go back to the previous tool self.canvas.setMapTool(self.active_map_tool_before_custom) def prepare_identify_plot(self): """ Custom Identify tool was activated, prepare everything for identifying plots """ self.active_map_tool_before_custom = self.canvas.mapTool() self.btn_identify_plot.setChecked(True) self.canvas.mapToolSet.connect(self.initialize_tools) if self._layers[self.names.OP_PLOT_T][LAYER] is None: self.add_layers() self.maptool_identify.setLayer( self._layers[self.names.OP_PLOT_T][LAYER]) cursor = QCursor() cursor.setShape(Qt.PointingHandCursor) self.maptool_identify.setCursor(cursor) self.canvas.setMapTool(self.maptool_identify) try: self.maptool_identify.featureIdentified.disconnect() except TypeError as e: pass self.maptool_identify.featureIdentified.connect(self.get_info_by_plot) def get_info_by_plot(self, plot_feature): plot_t_id = plot_feature[self.names.T_ID_F] self.canvas.flashFeatureIds(self._layers[self.names.OP_PLOT_T][LAYER], [plot_feature.id()], QColor(255, 0, 0, 255), QColor(255, 0, 0, 0), flashes=1, duration=500) with OverrideCursor(Qt.WaitCursor): if not self.isVisible(): self.show() self.search_data_by_component(plot_t_id=plot_t_id, zoom_and_select=False) self._layers[self.names.OP_PLOT_T][LAYER].selectByIds( [plot_feature.id()]) def search_data_by_component(self, **kwargs): self._layers[self.names.OP_PLOT_T][LAYER].removeSelection() # Read zoom_and_select parameter and remove it from kwargs bZoom = False if 'zoom_and_select' in kwargs: bZoom = kwargs['zoom_and_select'] del kwargs['zoom_and_select'] records = self._db.get_igac_basic_info(**kwargs) self.setup_tree_view(self.tree_view_basic, records) if bZoom: # Zoom to resulting plots 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.names.OP_PLOT_T][LAYER], self.names.T_ID_F, plot_t_ids, True, True) plot_ids = [feature.id() for feature in features] self.zoom_to_features_requested.emit( self._layers[self.names.OP_PLOT_T][LAYER], plot_ids, dict(), 500) self._layers[self.names.OP_PLOT_T][LAYER].selectByIds(plot_ids) records = self._db.get_igac_legal_info(**kwargs) self.setup_tree_view(self.tree_view_legal, records) records = self._db.get_igac_property_record_card_info(**kwargs) self.setup_tree_view(self.tree_view_property_record_card, records) records = self._db.get_igac_physical_info(**kwargs) self.setup_tree_view(self.tree_view_physical, records) records = self._db.get_igac_economic_info(**kwargs) self.setup_tree_view(self.tree_view_economic, records) def setup_tree_view(self, tree_view, records): """ Configure result tree views :param tree_view: :return: """ tree_view.setModel(TreeModel(self.names, data=records)) tree_view.expandAll() self.add_thumbnails_to_tree_view(tree_view) def add_thumbnails_to_tree_view(self, tree_view): """ Gets a list of model indexes corresponding to extFiles objects to show a preview :param model: :return: """ model = tree_view.model() indexes = model.getPixmapIndexList() for idx in indexes: url = model.data(idx, Qt.UserRole)['url'] res, image = self.download_image("{}{}".format( url, SUFFIX_GET_THUMBNAIL)) if res: pixmap = QPixmap() pixmap.loadFromData(image) label = QLabel() label.setPixmap(pixmap) tree_view.setIndexWidget(idx, label) def get_plot_t_ids_from_basic_info(self, records): res = [] if records: for record in records: if self.names.OP_PLOT_T in record: for element in record[self.names.OP_PLOT_T]: res.append(element['id']) return res def alphanumeric_query(self): """ Alphanumeric query """ option = self.cbo_parcel_fields.currentData() query = self.txt_alphanumeric_query.value() if query: if option == self.names.OP_PARCEL_T_FMI_F: self.search_data_by_component(parcel_fmi=query, zoom_and_select=True) elif option == self.names.OP_PARCEL_T_PARCEL_NUMBER_F: self.search_data_by_component(parcel_number=query, zoom_and_select=True) else: # previous_parcel_number self.search_data_by_component(previous_parcel_number=query, zoom_and_select=True) else: self.iface.messageBar().pushMessage( "Asistente LADM_COL", QCoreApplication.translate("DockWidgetQueries", "First enter a query")) def show_context_menu(self, point): tree_view = self.sender() index = tree_view.indexAt(point) context_menu = QMenu("Context menu") index_data = index.data(Qt.UserRole) if index_data is None: return if "value" in index_data: action_copy = QAction( QCoreApplication.translate("DockWidgetQueries", "Copy value")) action_copy.triggered.connect( partial(self.copy_value, index_data["value"])) context_menu.addAction(action_copy) context_menu.addSeparator() if "url" in index_data: action_open_url = QAction( QCoreApplication.translate("DockWidgetQueries", "Open URL")) action_open_url.triggered.connect( partial(self.open_url, index_data["url"])) context_menu.addAction(action_open_url) context_menu.addSeparator() # Configure actions for tables/layers if "type" in index_data and "id" in index_data: table_name = index_data["type"] table_package = LayerConfig.get_dict_table_package(self.names) t_id = index_data["id"] geometry_type = None if table_name in table_package and table_package[ table_name] == LADMNames.SPATIAL_UNIT_PACKAGE: # Layers in Spatial Unit package have double geometry, we need the polygon one geometry_type = QgsWkbTypes.PolygonGeometry if table_name == self.names.OP_PARCEL_T: if self._layers[ self.names.OP_PARCEL_T][LAYER] is None or self._layers[ self.names. OP_PLOT_T][LAYER] is None or self._layers[ self.names.COL_UE_BAUNIT_T][LAYER] is None: self.add_layers() layer = self._layers[self.names.OP_PARCEL_T][LAYER] self.iface.layerTreeView().setCurrentLayer(layer) else: layer = self.qgis_utils.get_layer(self._db, table_name, geometry_type, True) if layer is not None: if layer.isSpatial(): action_zoom_to_feature = QAction( QCoreApplication.translate( "DockWidgetQueries", "Zoom to {} with {}={}").format( table_name, self.names.T_ID_F, t_id)) action_zoom_to_feature.triggered.connect( partial(self.zoom_to_feature, layer, t_id)) context_menu.addAction(action_zoom_to_feature) if table_name == self.names.OP_PARCEL_T: # We show a handy option to zoom to related plots plot_ids = self.ladm_data.get_plots_related_to_parcels( self._db, [t_id], None, self._layers[self.names.OP_PLOT_T][LAYER], self._layers[self.names.COL_UE_BAUNIT_T][LAYER]) if plot_ids: action_zoom_to_plots = QAction( QCoreApplication.translate( "DockWidgetQueries", "Zoom to related plot(s)")) action_zoom_to_plots.triggered.connect( partial(self.zoom_to_plots, plot_ids)) context_menu.addAction(action_zoom_to_plots) action_open_feature_form = QAction( QCoreApplication.translate( "DockWidgetQueries", "Open form for {} with {}={}").format( table_name, self.names.T_ID_F, t_id)) action_open_feature_form.triggered.connect( partial(self.open_feature_form, layer, t_id)) context_menu.addAction(action_open_feature_form) if context_menu.actions(): context_menu.exec_(tree_view.mapToGlobal(point)) 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): feature = self.get_feature_from_t_id(layer, t_id) self.iface.mapCanvas().zoomToFeatureIds(layer, [feature.id()]) self.canvas.flashFeatureIds(layer, [feature.id()], QColor(255, 0, 0, 255), QColor(255, 0, 0, 0), flashes=1, duration=500) def open_feature_form(self, layer, t_id): feature = self.get_feature_from_t_id(layer, t_id) self.iface.openFeatureForm(layer, feature) def get_feature_from_t_id(self, layer, t_id): field_idx = layer.fields().indexFromName(self.names.T_ID_F) request = QgsFeatureRequest( QgsExpression("{}={}".format(self.names.T_ID_F, t_id))) request.setFlags(QgsFeatureRequest.NoGeometry) iterator = layer.getFeatures(request) feature = QgsFeature() res = iterator.nextFeature(feature) if res: return feature return None def zoom_to_plots(self, plot_ids): self.iface.mapCanvas().zoomToFeatureIds( self._layers[self.names.OP_PLOT_T][LAYER], plot_ids) self.canvas.flashFeatureIds(self._layers[self.names.OP_PLOT_T][LAYER], plot_ids, QColor(255, 0, 0, 255), QColor(255, 0, 0, 0), flashes=1, duration=500) def closeEvent(self, event): try: self.canvas.mapToolSet.disconnect(self.initialize_tools) except TypeError as e: pass self.canvas.setMapTool(self.active_map_tool_before_custom) 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 = "Downloading image from document repository (this might take a while)..." with ProcessWithStatus(msg): if self.qgis_utils.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)
class EdgeCreator(QDockWidget, gui_dckwdgt_edge_creator): def __init__(self, iface, canvas, l_vertex, l_edge, typo_nature_lim=[], user=None, auth_creator=[], parent=None): super(EdgeCreator, self).__init__(parent) self.setupUi(self) # Delete Widget on close event.. self.setAttribute(Qt.WA_DeleteOnClose) self.save = False self.iface = iface self.canvas = canvas self.l_edge = l_edge self.l_vertex = l_vertex self.typo_nature_lim = typo_nature_lim self.user = user self.auth_creator = auth_creator self.vertices = self.l_vertex.getFeatures() self.vtx_start = None self.vtx_end = None self.selected_vertices = [None, None] self.edge = None for i, vertex in enumerate(self.vertices): self.start_vtx_cmb.insertItem(i, str(vertex.id())) self.start_vtx_cmb.setItemData(i, vertex, 32) self.start_vtx_cmb.setCurrentIndex(-1) self.end_vtx_cmb.insertItem(i, str(vertex.id())) self.end_vtx_cmb.setItemData(i, vertex, 32) self.end_vtx_cmb.setCurrentIndex(-1) # Attribute: `lim_typologie_nature` for e in self.typo_nature_lim: self.typo_nat_cmb.addItem(e) # Attribute: `som_createur` for i, e in enumerate(self.auth_creator): self.createur_cmb.addItem(u"%s (%s)" % (e[1], e[0])) if self.user == e[0]: self.createur_cmb.setCurrentIndex(i) self.start_vtx_tb.clicked.connect(self.select_start_vertex_on_canvas) self.end_vtx_tb.clicked.connect(self.select_end_vertex_on_canvas) self.start_vtx_cmb.highlighted.connect(self.on_vtx_start_pressed) self.end_vtx_cmb.highlighted.connect(self.on_vtx_end_pressed) self.start_vtx_cmb.currentIndexChanged.connect( self.on_vtx_start_pressed) self.end_vtx_cmb.currentIndexChanged.connect(self.on_vtx_end_pressed) self.start_vtx_cmb.highlighted.connect(self.create_edge) self.end_vtx_cmb.highlighted.connect(self.create_edge) self.start_vtx_cmb.currentIndexChanged.connect(self.create_edge) self.end_vtx_cmb.currentIndexChanged.connect(self.create_edge) # Manage delim_pub_chk text self.delim_pub_chk.stateChanged.connect(self.settext_delim_pub_chk) self.valid_btn.accepted.connect(self.on_accepted) self.valid_btn.rejected.connect(self.on_rejected) self.valid_btn.button(QDialogButtonBox.Reset).clicked.connect( self.on_reset) # Set typo_nature to Limite privée (by default) self.typo_nat_cmb.setCurrentText('Limite privée') # Prompt message self.iface.messageBar().pushMessage(edge_crea_txt[0], edge_crea_txt[1], Qgis.Info, duration=10) # Launch the choice of first vertex self.start_vtx_tb.click() # Change the text of the delim_pub checkbox def settext_delim_pub_chk(self): if self.delim_pub_chk.isChecked(): self.delim_pub_chk.setText('oui') else: self.delim_pub_chk.setText('non') def closeEvent(self, event): if not self.save: self.on_rejected() def select_start_vertex_on_canvas(self): self.identify_start_vertex = QgsMapToolIdentifyFeature( self.canvas, self.l_vertex) self.identify_start_vertex.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_start_vertex.featureIdentified.connect( self.on_start_vertex_identified) self.canvas.setMapTool(self.identify_start_vertex) def select_end_vertex_on_canvas(self): self.identify_end_vertex = QgsMapToolIdentifyFeature( self.canvas, self.l_vertex) self.identify_end_vertex.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_end_vertex.featureIdentified.connect( self.on_end_vertex_identified) self.canvas.setMapTool(self.identify_end_vertex) def on_start_vertex_identified(self, feature): cb = self.start_vtx_cmb items = [cb.itemText(i) for i in range(cb.count())] for i, e in enumerate(items): if int(feature.id()) == int(e): cb.setCurrentIndex(i) self.end_vtx_tb.click() def on_end_vertex_identified(self, feature): cb = self.end_vtx_cmb items = [cb.itemText(i) for i in range(cb.count())] for i, e in enumerate(items): if int(feature.id()) == int(e): cb.setCurrentIndex(i) def on_vtx_start_pressed(self, idx): self.vtx_start = self.start_vtx_cmb.itemData(idx, 32) self.select_vertices(self.vtx_start, 0) self.end_vtx_cmb.setEnabled(True) self.end_vtx_tb.setEnabled(True) def on_vtx_end_pressed(self, idx): self.vtx_end = self.end_vtx_cmb.itemData(idx, 32) self.select_vertices(self.vtx_end, 1) self.createur_cmb.setEnabled(True) def select_vertices(self, feature, i): if feature: self.selected_vertices[i] = feature.id() else: self.selected_vertices[i] = None if not None in self.selected_vertices: self.l_vertex.selectByIds(self.selected_vertices) elif feature: self.l_vertex.selectByIds([feature.id()]) def unselect_vertices(self): self.l_vertex.selectByIds([]) def create_edge(self): # If edge already exists, delete it.. if self.edge: self.l_edge.deleteFeature(self.edge.id()) # Two vertices are needed.. if not self.vtx_start or not self.vtx_end: return self.canvas.refresh() # Two DIFFERENT vertices.. if self.vtx_start == self.vtx_end: return self.canvas.refresh() self.lim_ge_createur = self.auth_creator[ self.createur_cmb.currentIndex()][0] lim_typologie_nature = self.typo_nat_cmb.currentText() # Create line geometry.. line = QgsGeometry.fromPolylineXY([ self.vtx_start.geometry().asPoint(), self.vtx_end.geometry().asPoint() ]) self.original_l_edge = self.l_edge # Check if the lines intersects # Transform the delim_pub checkbox into the correct value lim_delim_pub = chkbox_to_truefalse(self.delim_pub_chk) to_create = check_limit_cross(line, self.original_l_edge, self.lim_ge_createur, lim_delim_pub, lim_typologie_nature, self.canvas, False) # Creation of the RFU objects in the layer if to_create: # Create the feature.. self.edge = create_nw_feat(self.l_edge, line, [NULL, NULL, NULL, NULL, NULL]) else: self.on_reset() self.canvas.refresh() def on_accepted(self): if not self.edge: return False self.lim_ge_createur = self.auth_creator[ self.createur_cmb.currentIndex()][0] # Transform the delim_pub checkbox into the correct value lim_delim_pub = chkbox_to_truefalse(self.delim_pub_chk) lim_typologie_nature = self.typo_nat_cmb.currentText() self.edge.setAttributes([ NULL, NULL, self.lim_ge_createur, lim_delim_pub, lim_typologie_nature ]) self.l_edge.updateFeature(self.edge) self.l_vertex.removeSelection() self.canvas.refresh() self.save = True self.close() def on_rejected(self): # Do not save the feature.. if self.edge: self.l_edge.deleteFeature(self.edge.id()) self.unselect_vertices() self.canvas.refresh() self.close() def on_reset(self): self.start_vtx_cmb.setCurrentIndex(-1) self.end_vtx_cmb.setCurrentIndex(-1) self.end_vtx_cmb.setEnabled(False) self.end_vtx_lab.setEnabled(False) self.end_vtx_tb.setEnabled(False) for i, e in enumerate(self.auth_creator): if self.user == e[0]: self.createur_cmb.setCurrentIndex(i) self.createur_cmb.setEnabled(False) self.createur_lab.setEnabled(False) self.unselect_vertices() self.canvas.refresh() self.start_vtx_tb.click()
class DockWidgetQueries(QgsDockWidget, DOCKWIDGET_UI): def __init__(self, iface, controller, parent=None): super(DockWidgetQueries, self).__init__(None) self.setupUi(self) self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.iface = iface self._controller = controller self.logger = Logger() self.app = AppInterface() self.canvas = iface.mapCanvas() self.active_map_tool_before_custom = None self._identify_tool = None self._fill_combos() self.btn_identify_plot.setIcon( QIcon(":/Asistente-LADM-COL/resources/images/spatial_unit.png")) self.tab_results.setTabEnabled( TAB_BASIC_INFO_INDEX, False) # TODO: Remove when queries support LevCat 1.2 self.tab_results.setTabEnabled( TAB_PHYSICAL_INFO_INDEX, False) # TODO: Remove when queries support LevCat 1.2 self.tab_results.setTabEnabled( TAB_ECONOMIC_INFO_INDEX, False) # TODO: Remove when queries support LevCat 1.2 self.tab_results.setCurrentIndex( TAB_LEGAL_INFO_INDEX ) # TODO: Remove when queries support LevCat 1.2 # Set connections self._controller.close_view_requested.connect(self._close_dock_widget) self.btn_alphanumeric_query.clicked.connect(self._alphanumeric_query) self.cbo_parcel_fields.currentIndexChanged.connect( self._search_field_updated) self.btn_identify_plot.clicked.connect(self._btn_plot_toggled) self.btn_query_informality.clicked.connect(self._query_informality) self.btn_next_informal_parcel.clicked.connect( self._query_next_informal_parcel) self.btn_previous_informal_parcel.clicked.connect( self._query_previous_informal_parcel) # Context menu self._set_context_menus() # Create maptool self.maptool_identify = QgsMapToolIdentifyFeature(self.canvas) self._initialize_field_values_line_edit() self._update_informal_controls() def _search_field_updated(self, index=None): self._initialize_field_values_line_edit() def _initialize_field_values_line_edit(self): self.txt_alphanumeric_query.setLayer(self._controller.parcel_layer()) idx = self._controller.parcel_layer().fields().indexOf( self.cbo_parcel_fields.currentData()) self.txt_alphanumeric_query.setAttributeIndex(idx) def _set_context_menus(self): self.tree_view_basic.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_basic.customContextMenuRequested.connect( self._show_context_menu) self.tree_view_legal.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_legal.customContextMenuRequested.connect( self._show_context_menu) self.tree_view_physical.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_physical.customContextMenuRequested.connect( self._show_context_menu) self.tree_view_economic.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_economic.customContextMenuRequested.connect( self._show_context_menu) def _close_dock_widget(self): # Deactivate custom tool and close dockwidget self._controller.disconnect_plot_layer() self._controller.disconnect_parcel_layer() self._initialize_tools(new_tool=None, old_tool=self.maptool_identify) self._btn_plot_toggled() self.close( ) # The user needs to use the menus again, which will start everything from scratch def _fill_combos(self): self.cbo_parcel_fields.clear() self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetQueries", "Parcel Number"), self._controller.parcel_number_name()) self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetQueries", "Previous Parcel Number"), self._controller.previous_parcel_number_name()) self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetQueries", "Folio de Matrícula Inmobiliaria"), self._controller.fmi_name()) def _initialize_tools(self, new_tool, old_tool): if self.maptool_identify == old_tool: # custom identify was deactivated try: self.canvas.mapToolSet.disconnect(self._initialize_tools) except TypeError as e: pass self.btn_identify_plot.setChecked(False) else: # custom identify was activated pass def _btn_plot_toggled(self): if self.btn_identify_plot.isChecked(): self._prepare_identify_plot() else: # The button was toggled and deactivated, go back to the previous tool self.canvas.setMapTool(self.active_map_tool_before_custom) def _prepare_identify_plot(self): """ Custom Identify tool was activated, prepare everything for identifying plots """ self.active_map_tool_before_custom = self.canvas.mapTool() self.btn_identify_plot.setChecked(True) self.canvas.mapToolSet.connect(self._initialize_tools) self.maptool_identify.setLayer(self._controller.plot_layer()) cursor = QCursor() cursor.setShape(Qt.PointingHandCursor) self.maptool_identify.setCursor(cursor) self.canvas.setMapTool(self.maptool_identify) try: self.maptool_identify.featureIdentified.disconnect() except TypeError as e: pass self.maptool_identify.featureIdentified.connect( self._search_data_by_plot) def _search_data_by_plot(self, plot_feature): plot_t_id = plot_feature[self._controller.t_id_name()] self.app.gui.flash_features(self._controller.plot_layer(), [plot_feature.id()]) with OverrideCursor(Qt.WaitCursor): if not self.isVisible(): self.show() self._search_data_by_component(plot_t_ids=[plot_t_id], zoom_and_select=False) self._controller.plot_layer().selectByIds([plot_feature.id()]) def _search_data_by_component(self, **kwargs): """ Perform the searches by component and fill tree views :param kwargs: A dict with search criteria. """ self._controller.plot_layer().removeSelection() # Read zoom_and_select parameter and remove it from kwargs bZoom = False if 'zoom_and_select' in kwargs: bZoom = kwargs['zoom_and_select'] del kwargs['zoom_and_select'] if 'parcel_number' in kwargs and kwargs['parcel_number'] == NULL: self.logger.warning( __name__, QCoreApplication.translate( "DockWidgetQueries", "The parcel number is NULL! We cannot retrieve data for parcels with NULL parcel numbers." )) # records = self._controller.search_data_basic_info(**kwargs) # if bZoom: # self._controller.zoom_to_resulting_plots(records) # self._setup_tree_view(self.tree_view_basic, records) records = self._controller.search_data_legal_info(**kwargs) self._setup_tree_view(self.tree_view_legal, records) # records = self._controller.search_data_physical_info(**kwargs) # self._setup_tree_view(self.tree_view_physical, records) # records = self._controller.search_data_economic_info(**kwargs) # self._setup_tree_view(self.tree_view_economic, records) def _setup_tree_view(self, tree_view, records): """ Configure result tree views :param tree_view: Tree view to be updated :param records: List of dicts. A dict per plot: {id: 21, attributes: {...}} """ tree_view.setModel(self._controller.create_model(records)) self._collapse_tree_view_items(tree_view) self._add_thumbnails_to_tree_view(tree_view) def _collapse_tree_view_items(self, tree_view): """ Collapse tree view items based on a property """ tree_view.expandAll() for idx in tree_view.model().getCollapseIndexList(): tree_view.collapse(idx) def _add_thumbnails_to_tree_view(self, tree_view): """ Gets a list of model indexes corresponding to extFiles objects to show a preview """ model = tree_view.model() for idx in model.getPixmapIndexList(): url = model.data(idx, Qt.UserRole)['url'] res, image = self._controller.download_image("{}{}".format( url, SUFFIX_GET_THUMBNAIL)) if res: pixmap = QPixmap() pixmap.loadFromData(image) label = QLabel() label.setPixmap(pixmap) tree_view.setIndexWidget(idx, label) def _alphanumeric_query(self): option = self.cbo_parcel_fields.currentData() query = self.txt_alphanumeric_query.value() if query: if option == self._controller.fmi_name(): self._search_data_by_component(parcel_fmi=query, zoom_and_select=True) elif option == self._controller.parcel_number_name(): self._search_data_by_component(parcel_number=query, zoom_and_select=True) else: # previous_parcel_number self._search_data_by_component(previous_parcel_number=query, zoom_and_select=True) else: self.logger.info_msg( __name__, QCoreApplication.translate("DockWidgetQueries", "First enter a query")) def _show_context_menu(self, point): tree_view = self.sender() index = tree_view.indexAt(point) context_menu = QMenu("Context menu") index_data = index.data(Qt.UserRole) if index_data is None: return if "value" in index_data: action_copy = QAction( QCoreApplication.translate("DockWidgetQueries", "Copy value")) action_copy.triggered.connect( partial(self._controller.copy_value, index_data["value"])) context_menu.addAction(action_copy) context_menu.addSeparator() if "url" in index_data: action_open_url = QAction( QCoreApplication.translate("DockWidgetQueries", "Open URL")) action_open_url.triggered.connect( partial(self._controller.open_url, index_data["url"])) context_menu.addAction(action_open_url) context_menu.addSeparator() # Configure actions for tables/layers if "type" in index_data and "id" in index_data: table_name = index_data["type"] t_id = index_data["id"] if table_name == self._controller.parcel_layer_name(): layer = self._controller.parcel_layer() self.app.core.activate_layer_requested.emit(layer) else: layer = self._controller.get_layer(table_name) if layer is not None: if layer.isSpatial(): action_zoom_to_feature = QAction( QCoreApplication.translate( "DockWidgetQueries", "Zoom to {} with {}={}").format( table_name, self._controller.t_id_name(), t_id)) action_zoom_to_feature.triggered.connect( partial(self._controller.zoom_to_feature, layer, t_id)) context_menu.addAction(action_zoom_to_feature) if table_name == self._controller.parcel_layer_name(): # We show a handy option to zoom to related plots plot_ids = self._controller.get_plots_related_to_parcel( t_id) if plot_ids: action_zoom_to_plots = QAction( QCoreApplication.translate( "DockWidgetQueries", "Zoom to related plot(s)")) action_zoom_to_plots.triggered.connect( partial(self._controller.zoom_to_plots, plot_ids)) context_menu.addAction(action_zoom_to_plots) action_open_feature_form = QAction( QCoreApplication.translate( "DockWidgetQueries", "Open form for {} with {}={}").format( table_name, self._controller.t_id_name(), t_id)) action_open_feature_form.triggered.connect( partial(self._controller.open_feature_form, layer, t_id)) context_menu.addAction(action_open_feature_form) if context_menu.actions(): context_menu.exec_(tree_view.mapToGlobal(point)) def _query_informality(self): first_parcel_number, current, total = self._controller.query_informal_parcels( ) self._search_data_by_component(parcel_number=first_parcel_number, zoom_and_select=True) self._update_informal_controls(first_parcel_number, current, total) if not total: self.logger.info_msg( __name__, QCoreApplication.translate( "DockWidgetQueries", "There are no informal parcels in this database!")) def _update_informal_controls(self, parcel_number='', current=0, total=0): """ Update controls (reset labels, enable buttons if we have informality) """ self._update_informal_labels(parcel_number, current, total) self.btn_query_informality.setText( QCoreApplication.translate("DockWidgetQueries", "Restart" ) if current else QCoreApplication. translate("DockWidgetQueries", "Start")) enable = total > 1 # At least 2 to enable buttons that traverse the parcels self.btn_next_informal_parcel.setEnabled(enable) self.btn_previous_informal_parcel.setEnabled(enable) def _update_informal_labels(self, parcel_number='', current=0, total=0): self.lbl_informal_parcel_number.setText( parcel_number if parcel_number != NULL else 'NULL') out_of = '' if current and total: out_of = QCoreApplication.translate("DockWidgetQueries", "{} out of {}").format( current, total) self.lbl_informal_out_of_total.setText(out_of) def _query_next_informal_parcel(self): parcel_number, current, total = self._controller.get_next_informal_parcel( ) self._search_data_by_component(parcel_number=parcel_number, zoom_and_select=True) self._update_informal_controls(parcel_number, current, total) def _query_previous_informal_parcel(self): parcel_number, current, total = self._controller.get_previous_informal_parcel( ) self._search_data_by_component(parcel_number=parcel_number, zoom_and_select=True) self._update_informal_controls(parcel_number, current, total) def closeEvent(self, event): try: self.canvas.mapToolSet.disconnect(self._initialize_tools) except TypeError as e: pass self.canvas.setMapTool(self.active_map_tool_before_custom)
class DockWidgetQueries(QgsDockWidget, DOCKWIDGET_UI): def __init__(self, iface, db, qgis_utils, ladm_data, parent=None): super(DockWidgetQueries, self).__init__(None) self.setupUi(self) self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.iface = iface self.canvas = iface.mapCanvas() self._db = db self.qgis_utils = qgis_utils self.ladm_data = ladm_data self.selection_color = None self.active_map_tool_before_custom = None self.clipboard = QApplication.clipboard() # Required layers self._plot_layer = None self._parcel_layer = None self._uebaunit_table = None self._identify_tool = None self.add_layers() self.fill_combos() self.btn_identify_plot.setIcon( QIcon(":/Asistente-LADM_COL/resources/images/spatial_unit.png")) # Set connections self.btn_alphanumeric_query.clicked.connect(self.alphanumeric_query) self.btn_clear_alphanumeric_query.clicked.connect( self.clear_alphanumeric_query) self.btn_identify_plot.clicked.connect(self.btn_plot_toggled) # Context menu self._set_context_menus() # Create maptool self.maptool_identify = QgsMapToolIdentifyFeature(self.canvas) def _set_context_menus(self): self.tree_view_basic.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_basic.customContextMenuRequested.connect( self.show_context_menu) self.tree_view_legal.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_legal.customContextMenuRequested.connect( self.show_context_menu) self.tree_view_property_record_card.setContextMenuPolicy( Qt.CustomContextMenu) self.tree_view_property_record_card.customContextMenuRequested.connect( self.show_context_menu) self.tree_view_physical.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_physical.customContextMenuRequested.connect( self.show_context_menu) self.tree_view_economic.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_economic.customContextMenuRequested.connect( self.show_context_menu) def add_layers(self): res_layers = self.qgis_utils.get_layers(self._db, { PLOT_TABLE: { 'name': PLOT_TABLE, 'geometry': QgsWkbTypes.PolygonGeometry }, PARCEL_TABLE: { 'name': PARCEL_TABLE, 'geometry': None }, UEBAUNIT_TABLE: { 'name': UEBAUNIT_TABLE, 'geometry': None } }, load=True) self._plot_layer = res_layers[PLOT_TABLE] if self._plot_layer is None: self.iface.messageBar().pushMessage( "Asistente LADM_COL", QCoreApplication.translate( "DockWidgetQueries", "Plot layer couldn't be found... {}").format( self._db.get_description()), Qgis.Warning) else: # Layer was found, listen to its removal so that we can deactivate the custom tool when that occurs try: self._plot_layer.willBeDeleted.disconnect(self.layer_removed) except TypeError as e: pass self._plot_layer.willBeDeleted.connect(self.layer_removed) self._parcel_layer = res_layers[PARCEL_TABLE] if self._parcel_layer is None: self.iface.messageBar().pushMessage( "Asistente LADM_COL", QCoreApplication.translate( "DockWidgetQueries", "Parcel layer couldn't be found... {}").format( self._db.get_description()), Qgis.Warning) else: # Layer was found, listen to its removal so that we can update the variable properly try: self._parcel_layer.willBeDeleted.disconnect( self.parcel_layer_removed) except TypeError as e: pass self._parcel_layer.willBeDeleted.connect(self.parcel_layer_removed) self._uebaunit_table = res_layers[UEBAUNIT_TABLE] if self._uebaunit_table is None: self.iface.messageBar().pushMessage( "Asistente LADM_COL", QCoreApplication.translate( "DockWidgetQueries", "UEBAUnit table couldn't be found... {}").format( self._db.get_description()), Qgis.Warning) else: # Layer was found, listen to its removal so that we can update the variable properly try: self._uebaunit_table.willBeDeleted.disconnect( self.uebaunit_table_removed) except TypeError as e: pass self._uebaunit_table.willBeDeleted.connect( self.uebaunit_table_removed) def initialize_tool(self): self._plot_layer = None self.initialize_tools(new_tool=None, old_tool=self.maptool_identify) self.btn_plot_toggled() def update_db_connection(self, db, ladm_col_db): self._db = db self.initialize_tool() if not ladm_col_db: self.setVisible(False) def layer_removed(self): # The required layer was removed, deactivate custom tool self.initialize_tool() def parcel_layer_removed(self): self._parcel_layer = None def uebaunit_table_removed(self): self._uebaunit_table = None def fill_combos(self): self.cbo_parcel_fields.clear() if self._parcel_layer is not None: self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetQueries", "Parcel Number"), 'parcel_number') self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetQueries", "Previous Parcel Number"), 'previous_parcel_number') self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetQueries", "Folio de Matrícula Inmobiliaria"), 'fmi') else: self.add_layers() def initialize_tools(self, new_tool, old_tool): if self.maptool_identify == old_tool: # custom identify was deactivated try: self.canvas.mapToolSet.disconnect(self.initialize_tools) except TypeError as e: pass if self.selection_color is not None: self.canvas.setSelectionColor( self.selection_color ) # Original selection color set in QGIS self.btn_identify_plot.setChecked(False) else: # custom identify was activated pass def btn_plot_toggled(self): if self.btn_identify_plot.isChecked(): self.prepare_identify_plot() else: # The button was toggled and deactivated, go back to the previous tool self.canvas.setMapTool(self.active_map_tool_before_custom) def prepare_identify_plot(self): """ Custom Identify tool was activated, prepare everything for identifying plots """ self.active_map_tool_before_custom = self.canvas.mapTool() self.selection_color = self.canvas.selectionColor( ) # Probably QColor('#ffff00') self.btn_identify_plot.setChecked(True) self.canvas.mapToolSet.connect(self.initialize_tools) self.canvas.setSelectionColor(QColor("red")) if self._plot_layer is None: self.add_layers() self.maptool_identify.setLayer(self._plot_layer) cursor = QCursor() cursor.setShape(Qt.PointingHandCursor) self.maptool_identify.setCursor(cursor) self.canvas.setMapTool(self.maptool_identify) try: self.maptool_identify.featureIdentified.disconnect() except TypeError as e: pass self.maptool_identify.featureIdentified.connect(self.get_info_by_plot) def get_info_by_plot(self, plot_feature): plot_t_id = plot_feature[ID_FIELD] self.canvas.flashFeatureIds(self._plot_layer, [plot_feature.id()], QColor(255, 0, 0, 255), QColor(255, 0, 0, 0), flashes=1, duration=500) with OverrideCursor(Qt.WaitCursor): self._plot_layer.selectByIds([plot_feature.id()]) if not self.isVisible(): self.show() self.search_data_by_component(plot_t_id=plot_t_id) def search_data_by_component(self, **kwargs): records = self._db.get_igac_basic_info(**kwargs) self.tree_view_basic.setModel(TreeModel(data=records)) self.tree_view_basic.expandAll() records = self._db.get_igac_legal_info(**kwargs) self.tree_view_legal.setModel(TreeModel(data=records)) self.tree_view_legal.expandAll() records = self._db.get_igac_property_record_card_info(**kwargs) self.tree_view_property_record_card.setModel(TreeModel(data=records)) self.tree_view_property_record_card.expandAll() records = self._db.get_igac_physical_info(**kwargs) self.tree_view_physical.setModel(TreeModel(data=records)) self.tree_view_physical.expandAll() records = self._db.get_igac_economic_info(**kwargs) self.tree_view_economic.setModel(TreeModel(data=records)) self.tree_view_economic.expandAll() def alphanumeric_query(self): """ Alphanumeric query """ option = self.cbo_parcel_fields.currentData() query = self.txt_alphanumeric_query.text().strip() if query: if option == 'fmi': self.search_data_by_component(parcel_fmi=query) elif option == 'parcel_number': self.search_data_by_component(parcel_number=query) else: # previous_parcel_number self.search_data_by_component(previous_parcel_number=query) else: self.iface.messageBar().pushMessage( "Asistente LADM_COL", QCoreApplication.translate("DockWidgetQueries", "First enter a query")) def clear_alphanumeric_query(self): self.txt_alphanumeric_query.setText('') def show_context_menu(self, point): tree_view = self.sender() index = tree_view.indexAt(point) context_menu = QMenu("Context menu") index_data = index.data(Qt.UserRole) if index_data is None: return if "value" in index_data: action_copy = QAction( QCoreApplication.translate("DockWidgetQueries", "Copy value")) action_copy.triggered.connect( partial(self.copy_value, index_data["value"])) context_menu.addAction(action_copy) context_menu.addSeparator() # Configure actions for tables/layers if "type" in index_data and "id" in index_data: table_name = index_data["type"] t_id = index_data["id"] geometry_type = None if table_name in DICT_TABLE_PACKAGE and DICT_TABLE_PACKAGE[ table_name] == SPATIAL_UNIT_PACKAGE: # Layers in Spatial Unit package have double geometry, we need the polygon one geometry_type = QgsWkbTypes.PolygonGeometry if table_name == PARCEL_TABLE: if self._parcel_layer is None or self._plot_layer is None or self._uebaunit_table is None: self.add_layers() layer = self._parcel_layer self.iface.layerTreeView().setCurrentLayer(layer) else: layer = self.qgis_utils.get_layer(self._db, table_name, geometry_type, True) if layer is not None: if layer.isSpatial(): action_zoom_to_feature = QAction( QCoreApplication.translate( "DockWidgetQueries", "Zoom to {} with {}={}").format( table_name, ID_FIELD, t_id)) action_zoom_to_feature.triggered.connect( partial(self.zoom_to_feature, layer, t_id)) context_menu.addAction(action_zoom_to_feature) if table_name == PARCEL_TABLE: # We show a handy option to zoom to related plots plot_ids = self.ladm_data.get_plots_related_to_parcel( self._db, t_id, None, self._plot_layer, self._uebaunit_table) if plot_ids: action_zoom_to_plots = QAction( QCoreApplication.translate( "DockWidgetQueries", "Zoom to related plot(s)")) action_zoom_to_plots.triggered.connect( partial(self.zoom_to_plots, plot_ids)) context_menu.addAction(action_zoom_to_plots) action_open_feature_form = QAction( QCoreApplication.translate( "DockWidgetQueries", "Open form for {} with {}={}").format( table_name, ID_FIELD, t_id)) action_open_feature_form.triggered.connect( partial(self.open_feature_form, layer, t_id)) context_menu.addAction(action_open_feature_form) if context_menu.actions(): context_menu.exec_(tree_view.mapToGlobal(point)) def copy_value(self, value): self.clipboard.setText(str(value)) def zoom_to_feature(self, layer, t_id): feature = self.get_feature_from_t_id(layer, t_id) self.iface.mapCanvas().zoomToFeatureIds(layer, [feature.id()]) self.canvas.flashFeatureIds(layer, [feature.id()], QColor(255, 0, 0, 255), QColor(255, 0, 0, 0), flashes=1, duration=500) def open_feature_form(self, layer, t_id): feature = self.get_feature_from_t_id(layer, t_id) self.iface.openFeatureForm(layer, feature) def get_feature_from_t_id(self, layer, t_id): field_idx = layer.fields().indexFromName(ID_FIELD) request = QgsFeatureRequest( QgsExpression("{}={}".format( ID_FIELD, t_id))).setSubsetOfAttributes([field_idx]) request.setFlags(QgsFeatureRequest.NoGeometry) iterator = layer.getFeatures(request) feature = QgsFeature() res = iterator.nextFeature(feature) if res: return feature return None def zoom_to_plots(self, plot_ids): self.iface.mapCanvas().zoomToFeatureIds(self._plot_layer, plot_ids) self.canvas.flashFeatureIds(self._plot_layer, plot_ids, QColor(255, 0, 0, 255), QColor(255, 0, 0, 0), flashes=1, duration=500)
class EdgeCreator(QDockWidget, gui_dckwdgt_edge_creator): def __init__(self, canvas, l_vertex, l_edge, user=None, auth_creator=[], parent=None): super(EdgeCreator, self).__init__(parent) self.setupUi(self) # Delete Widget on close event.. self.setAttribute(Qt.WA_DeleteOnClose) self.save = False self.canvas = canvas self.l_edge = l_edge self.l_vertex = l_vertex self.user = user self.auth_creator = auth_creator self.vertices = self.l_vertex.getFeatures() self.vtx_start = None self.vtx_end = None self.selected_vertices = [None, None] self.edge = None for i, vertex in enumerate(self.vertices): self.startVertexComboBox.insertItem(i, str(vertex.id())) self.startVertexComboBox.setItemData(i, vertex, 32) self.startVertexComboBox.setCurrentIndex(-1) self.endVertexComboBox.insertItem(i, str(vertex.id())) self.endVertexComboBox.setItemData(i, vertex, 32) self.endVertexComboBox.setCurrentIndex(-1) # Attribute: `som_createur` for i, e in enumerate(self.auth_creator): self.creatorComboBox.addItem(u"%s (%s)" % (e[1], e[0])) if self.user == e[0]: self.creatorComboBox.setCurrentIndex(i) self.startVertextoolButton.clicked.connect(self.select_start_vertex_on_canvas) self.endVertextoolButton.clicked.connect(self.select_end_vertex_on_canvas) self.startVertexComboBox.highlighted.connect(self.on_vtx_start_pressed) self.endVertexComboBox.highlighted.connect(self.on_vtx_end_pressed) self.startVertexComboBox.currentIndexChanged.connect(self.on_vtx_start_pressed) self.endVertexComboBox.currentIndexChanged.connect(self.on_vtx_end_pressed) self.startVertexComboBox.highlighted.connect(self.create_edge) self.endVertexComboBox.highlighted.connect(self.create_edge) self.startVertexComboBox.currentIndexChanged.connect(self.create_edge) self.endVertexComboBox.currentIndexChanged.connect(self.create_edge) self.buttonBox.accepted.connect(self.on_accepted) self.buttonBox.rejected.connect(self.on_rejected) self.buttonBox.button(QDialogButtonBox.Reset).clicked.connect(self.on_reset) def closeEvent(self, event): if not self.save: self.on_rejected() def select_start_vertex_on_canvas(self): self.identify_start_vertex = QgsMapToolIdentifyFeature(self.canvas, self.l_vertex) self.identify_start_vertex.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_start_vertex.featureIdentified.connect(self.on_start_vertex_identified) self.canvas.setMapTool(self.identify_start_vertex) def select_end_vertex_on_canvas(self): self.identify_end_vertex = QgsMapToolIdentifyFeature(self.canvas, self.l_vertex) self.identify_end_vertex.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_end_vertex.featureIdentified.connect(self.on_end_vertex_identified) self.canvas.setMapTool(self.identify_end_vertex) def on_start_vertex_identified(self, feature): cb = self.startVertexComboBox items = [cb.itemText(i) for i in range(cb.count())] for i, e in enumerate(items): if int(feature.id()) == int(e): cb.setCurrentIndex(i) def on_end_vertex_identified(self, feature): cb = self.endVertexComboBox items = [cb.itemText(i) for i in range(cb.count())] for i, e in enumerate(items): if int(feature.id()) == int(e): cb.setCurrentIndex(i) def on_vtx_start_pressed(self, idx): self.vtx_start = self.startVertexComboBox.itemData(idx, 32) self.select_vertices(self.vtx_start, 0) self.endVertexComboBox.setEnabled(True) self.endVertextoolButton.setEnabled(True) def on_vtx_end_pressed(self, idx): self.vtx_end = self.endVertexComboBox.itemData(idx, 32) self.select_vertices(self.vtx_end, 1) self.creatorComboBox.setEnabled(True) def select_vertices(self, feature, i): if feature: self.selected_vertices[i] = feature.id() else: self.selected_vertices[i] = None self.l_vertex.setSelectedFeatures(self.selected_vertices) def unselect_vertices(self): self.l_vertex.setSelectedFeatures([]) def create_edge(self): # If edge already exists, delete it.. if self.edge: self.l_edge.deleteFeature(self.edge.id()) # Two vertices are needed.. if not self.vtx_start or not self.vtx_end: return self.canvas.refresh() # Two DIFFERENT vertices.. if self.vtx_start == self.vtx_end: return self.canvas.refresh() # Create line geometry.. line = QgsGeometry.fromPolyline([self.vtx_start.geometry().asPoint(), self.vtx_end.geometry().asPoint()]) # Create the feature.. self.edge = QgsFeature() self.edge.setGeometry(line) self.edge.setFields(self.l_edge.pendingFields()) self.edge.setAttributes( [QPyNullVariant(int), QPyNullVariant(int), QPyNullVariant(int)]) # Add feature to layer.. self.l_edge.addFeature(self.edge) self.canvas.refresh() def on_accepted(self): if not self.edge: return False self.lim_ge_createur = self.auth_creator[self.creatorComboBox.currentIndex()][0] self.edge.setAttributes( [QPyNullVariant(int), QPyNullVariant(int), self.lim_ge_createur]) self.l_edge.updateFeature(self.edge) self.canvas.refresh() self.save = True self.close() def on_rejected(self): # Do not save the feature.. if self.edge: self.l_edge.deleteFeature(self.edge.id()) self.unselect_vertices() self.canvas.refresh() self.close() def on_reset(self): self.startVertexComboBox.setCurrentIndex(0) # self.startVertexComboBox.setEnabled(True) # self.startVertexLabel.setEnabled(True) self.endVertexComboBox.setCurrentIndex(0) self.endVertexComboBox.setEnabled(False) self.endVertexLabel.setEnabled(False) self.endVertextoolButton.setEnabled(False) for i, e in enumerate(self.auth_creator): if self.user == e[0]: self.creatorComboBox.setCurrentIndex(i) self.creatorComboBox.setEnabled(False) self.creatorLabel.setEnabled(False) self.unselect_vertices() self.canvas.refresh()
class EditorRFUGeofoncier: def __init__(self, iface): # Save reference to the QGIS interface self.iface = iface self.canvas = self.iface.mapCanvas() self.project = QgsProject.instance() # Initialize plugin directory self.plugin_dir = os.path.dirname(__file__) self.conn = None self.rfu = None self.edge_creator = None self.tol_spt = 0.0 self.dxf2rfu_import = None self.csv2rfu_import = None self.show_ptplots = None def unload(self): # Remove the plugin menu and toolbar if self.rfu_menu != None: self.iface.mainWindow().menuBar().removeAction( self.rfu_menu.menuAction()) self.rfu_menu.deleteLater() self.iface.mainWindow().removeToolBar(self.toolbar) else: self.iface.removePluginMenu("&RFU", self.rfu_menu.menuAction()) self.rfu_menu.deleteLater() # Remove RFU dockwidgets if self.rfu: self.iface.removeDockWidget(self.rfu) if self.edge_creator: self.iface.removeDockWidget(self.edge_creator) def initGui(self): # Add specific menu to QGIS menu self.rfu_menu = QMenu(QCoreApplication.translate("RFU", mnu_title_txt)) self.iface.mainWindow().menuBar().insertMenu( self.iface.firstRightStandardMenu().menuAction(), self.rfu_menu) # Add specific toolbar self.toolbar = self.iface.addToolBar(mnu_title_txt) self.toolbar.setObjectName("GeofoncierRfuEditorToolBar") # Create actions self.action_login = QAction(QIcon(r":/resources/rfu_btn_log_in"), "S'identifer", self.iface.mainWindow()) self.action_login.setEnabled(True) self.action_login.setCheckable(True) self.action_connector = QAction(QIcon(r":/resources/rfu_btn_conn_rfu"), "Connection à l'API Géofoncier", self.iface.mainWindow()) self.action_connector.setEnabled(False) self.action_connector.setCheckable(True) self.action_vtx_creator = QAction( QIcon(r":/resources/rfu_btn_add_vtx"), "Ajouter un sommet RFU", self.iface.mainWindow()) self.action_edge_creator = QAction( QIcon(r":/resources/rfu_btn_add_edge"), "Ajouter une limite RFU", self.iface.mainWindow()) self.action_edge_creator.setCheckable(True) self.action_import_csv2rfu = QAction( QIcon(r":/resources/rfu_btn_import_csvrfu"), "Importer un fichier CSV spécifique RFU", self.iface.mainWindow()) self.action_import_dxf2rfu = QAction( QIcon(r":/resources/rfu_btn_import_dxf2rfu"), "Importer un fichier DXF filtré pour le RFU", self.iface.mainWindow()) self.action_cut_oldlimit = QAction( QIcon(r":/resources/rfu_btn_cut_oldlimit"), "Couper une limite existante par un ou plusieurs sommets nouveaux", self.iface.mainWindow()) self.action_transfo_pt_to_plot = QAction( QIcon(r":/resources/rfu_btn_pt_to_plot"), "Traiter les sommets proches à transformer en détermination", self.iface.mainWindow()) self.action_del_ptplot = QAction( QIcon(r":/resources/rfu_btn_del_ptplot"), "Supprimer une détermination d'un sommet", self.iface.mainWindow()) self.action_show_ptplots = QAction( QIcon(r":/resources/rfu_btn_show_ptplots"), "Consulter les déterminations d'un sommet", self.iface.mainWindow()) self.action_show_capabilities = QAction( QIcon(r":/resources/rfu_btn_show_capabilities"), "Visualiser les paramètres de l'application", self.iface.mainWindow()) self.action_show_capabilities.setEnabled(False) # Deactivate creation and import tools self.allow_creation(False) # Add actions to the toolbar self.toolbar.addActions([ self.action_login, self.action_connector, self.action_vtx_creator, self.action_edge_creator, self.action_import_csv2rfu, self.action_import_dxf2rfu, self.action_cut_oldlimit, self.action_transfo_pt_to_plot, self.action_del_ptplot, self.action_show_ptplots, self.action_show_capabilities ]) # Add actions to the menu self.rfu_menu.addActions([ self.action_login, self.action_connector, self.action_vtx_creator, self.action_edge_creator, self.action_import_csv2rfu, self.action_import_dxf2rfu, self.action_cut_oldlimit, self.action_transfo_pt_to_plot, self.action_del_ptplot, self.action_show_ptplots, self.action_show_capabilities ]) # Manage signals.. self.iface.currentLayerChanged.connect(self.on_toggled) self.project.layersRemoved.connect(self.on_layers_removed) self.action_login.triggered.connect(self.tool_login_on_triggered) self.action_connector.triggered[bool].connect( self.tool_rfu_on_triggered) self.action_vtx_creator.triggered.connect( self.tool_vtx_creator_on_triggered) self.action_edge_creator.triggered[bool].connect( self.tool_edge_creator_on_triggered) self.action_import_csv2rfu.triggered.connect(self.tool_import_csvrfu) self.action_import_dxf2rfu.triggered.connect(self.tool_import_dxf2rfu) self.action_cut_oldlimit.triggered.connect(self.tool_cut_oldlimit) self.action_transfo_pt_to_plot.triggered.connect( self.tool_transfo_pt_to_plot) self.action_del_ptplot.triggered.connect( partial(self.tool_select_pt_to_plot, "del")) self.action_show_ptplots.triggered.connect( partial(self.tool_select_pt_to_plot, "info")) self.action_show_capabilities.triggered.connect( self.tool_show_capabilities) # Initialize current layer to None (See switch_editing()).. self.current_layer = None # On iface Signals # ================ def on_toggled(self): layer = self.canvas.currentLayer() if not layer or not self.rfu: return if layer.isEditable() and layer == self.rfu.l_vertex: self.switch_editing(layer) elif layer.isEditable() and layer == self.rfu.l_edge: self.switch_editing(layer) def switch_editing(self, layer): old_layer = None if self.current_layer is not None: old_layer = self.current_layer old_layer.committedFeaturesAdded.disconnect( self.on_committed_features_added) old_layer.committedFeaturesRemoved.disconnect( self.on_committed_features_removed) old_layer.attributeValueChanged.disconnect( self.on_attribute_value_changed) old_layer.geometryChanged.disconnect(self.on_geometry_changed) self.current_layer = layer layer.committedFeaturesAdded.connect(self.on_committed_features_added) layer.committedFeaturesRemoved.connect( self.on_committed_features_removed) layer.attributeValueChanged.connect(self.on_attribute_value_changed) layer.geometryChanged.connect(self.on_geometry_changed) def on_committed_features_added(self, layer_id, features): self.rfu.add_features(layer_id, features) def on_committed_features_removed(self, layer_id, ft_id_list): self.rfu.remove_features(layer_id, ft_id_list) def on_geometry_changed(self, fid, geom): feature = tools.get_feature_by_id(self.current_layer, fid) self.rfu.modify_feature(self.current_layer.id(), feature) def on_attribute_value_changed(self, fid, field_idx, value): feature = tools.get_feature_by_id(self.current_layer, fid) self.rfu.modify_feature(self.current_layer.id(), feature) # On map layer registry signals # ============================= def on_layers_removed(self, layers): self.current_layer = None # Login/logout # ============ def open_connection(self): dlg_login = GeoFoncierAPILogin() dlg_login.closed.connect(self.dlg_login_on_closed) dlg_login.opened.connect(self.dlg_login_on_opened) dlg_login.show() if not dlg_login.exec_(): return None self.conn = dlg_login.conn self.action_connector.setEnabled(True) self.action_show_capabilities.setEnabled(True) self.iface.messageBar().pushMessage("Géofoncier", "Bonjour %s %s." % (self.conn.prenom, self.conn.nom), Qgis.Info, duration=6) def close_connection(self): msg = ("Voulez-vous fermer votre session ?\n" "Attention, toute modification sera perdue.") resp = QMessageBox.question(self.iface.mainWindow(), r"Question", msg, QMessageBox.Yes, QMessageBox.No) if resp != QMessageBox.Yes: self.dlg_login_on_closed() return False # Close connection if self.rfu: if self.rfu: self.rfu.reset() try: self.rfu.disconn_scale_limit() except: pass self.rfu.close() self.action_connector.setChecked(False) self.action_connector.setEnabled(False) self.action_show_capabilities.setEnabled(False) self.allow_creation(False) self.conn = None self.iface.messageBar().pushMessage("Géofoncier", "À bientôt.", Qgis.Info, duration=6) # On action signals # ================= def dlg_login_on_closed(self): if self.conn == None: self.action_login.setChecked(False) else: self.action_login.setChecked(True) def dlg_login_on_opened(self): self.action_login.setChecked(True) def tool_login_on_triggered(self, checked): if checked: self.open_connection() else: self.close_connection() def tool_rfu_on_triggered(self, checked): if checked and not self.rfu: self.rfu = RFUDockWidget(self.iface, self.canvas, self.project, conn=self.conn) self.rfu.setObjectName(r"RFUDockWidget") self.iface.addDockWidget(Qt.TopDockWidgetArea, self.rfu) self.rfu.closed.connect(self.rfu_on_closed) self.rfu.uploaded.connect(self.rfu_on_uploaded) self.rfu.downloaded.connect(self.rfu_on_downloaded) self.rfu.rfureset.connect(self.rfu_on_reset) if checked and self.rfu: self.rfu.show() if not checked: self.rfu.hide() def rfu_on_closed(self): self.action_connector.setChecked(False) def rfu_on_uploaded(self): if self.edge_creator: self.on_edge_creator_destroyed() # Change the current layer self.iface.setActiveLayer(self.rfu.l_edge) self.iface.setActiveLayer(self.rfu.l_vertex) def rfu_on_downloaded(self): # Allow creation and import self.allow_creation(True) # Change the current layer self.iface.setActiveLayer(self.rfu.l_edge) self.iface.setActiveLayer(self.rfu.l_vertex) def rfu_on_reset(self): # Allow creation and import self.allow_creation(False) def tool_vtx_creator_on_triggered(self): # Set the layer l_vertex current self.iface.setActiveLayer(self.rfu.l_vertex) self.project.layerTreeRoot().findLayer( self.rfu.l_vertex.id()).setItemVisibilityChecked(True) self.canvas.refresh() # Check the editable mode if not self.rfu.l_vertex.isEditable(): self.rfu.l_vertex.startEditing() if not self.rfu.dflt_ellips_acronym: self.rfu.selected_ellips_acronym = self.rfu.dflt_ellips_acronym dlg_vtx_creator = VertexCreator( self.canvas, self.project, self.rfu.layers[0], user=self.rfu.conn.user, precision_class=self.rfu.precision_class, ellips_acronym=self.rfu.ellips_acronym, selected_ellips_acronym=self.rfu.selected_ellips_acronym, typo_nature_som=self.rfu.typo_nature_som, auth_creator=self.rfu.auth_creator, tol_spt=self.rfu.tol_same_pt) dlg_vtx_creator.show() if not dlg_vtx_creator.exec_(): return None def tool_edge_creator_on_triggered(self, checked=False): if not checked: self.edge_creator.close() self.edge_creator = None if checked: # Set the layer l_edge current self.iface.setActiveLayer(self.rfu.l_edge) self.project.layerTreeRoot().findLayer( self.rfu.l_edge.id()).setItemVisibilityChecked(True) self.canvas.refresh() # Check the editable mode if not self.rfu.l_edge.isEditable(): self.rfu.l_edge.startEditing() self.edge_creator = EdgeCreator( self.iface, self.canvas, self.rfu.layers[0], self.rfu.layers[1], typo_nature_lim=self.rfu.typo_nature_lim, user=self.rfu.conn.user, auth_creator=self.rfu.auth_creator) self.edge_creator.setObjectName(r"EdgeCreatorDockWidget") self.edge_creator.destroyed.connect(self.on_edge_creator_destroyed) self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.edge_creator) def on_edge_creator_destroyed(self): self.edge_creator = None return self.action_edge_creator.setChecked(False) # Launch the import csv tool def tool_import_csvrfu(self): if self.rfu: self.csv2rfu_import = ImportCsvRfu( self.iface, self.canvas, self.project, self.rfu.layers[0], self.rfu.layers[1], user=self.rfu.conn.user, auth_creator=self.rfu.auth_creator, precision_class=self.rfu.precision_class, ellips_acronym=self.rfu.ellips_acronym, selected_ellips_acronym=self.rfu.selected_ellips_acronym, typo_nature_som=self.rfu.typo_nature_som, typo_nature_lim=self.rfu.typo_nature_lim, tol_spt=self.rfu.tol_same_pt) self.csv2rfu_import.import_file() else: QMessageBox.information(self.iface.mainWindow(), tl_imp_canc, txt_csvimp_norfu_canc) # Launch the import dxf tool def tool_import_dxf2rfu(self): if self.rfu: self.dxf2rfu_import = ImportDxf2Rfu( self.iface, self.canvas, self.project, self.rfu.layers[0], self.rfu.layers[1], user=self.rfu.conn.user, auth_creator=self.rfu.auth_creator, precision_class=self.rfu.precision_class, ellips_acronym=self.rfu.ellips_acronym, selected_ellips_acronym=self.rfu.selected_ellips_acronym, typo_nature_som=self.rfu.typo_nature_som, typo_nature_lim=self.rfu.typo_nature_lim, tol_spt=self.rfu.tol_same_pt) self.dxf2rfu_import.import_file() else: QMessageBox.information(self.iface.mainWindow(), tl_imp_canc, txt_dxfimp_norfu_canc) # Cut an old limit at the point of a new vertex def tool_cut_oldlimit(self): if self.rfu and self.rfu.layers[0]: # Set the layer l_vertex current self.iface.setActiveLayer(self.rfu.l_vertex) self.project.layerTreeRoot().findLayer( self.rfu.l_vertex.id()).setItemVisibilityChecked(True) self.canvas.refresh() # Check the editable mode if not self.rfu.l_vertex.isEditable(): self.rfu.l_vertex.startEditing() self.tr_cut_oldlimit = CutOldLimit( self.canvas, self.project, self.rfu.layers[0], self.rfu.layers[1], ) # # Modal window # self.tr_pt_to_plot.setWindowModality(Qt.ApplicationModal) self.tr_cut_oldlimit.show() else: QMessageBox.information(self.iface.mainWindow(), tr_pttoplot_imp_msg[0], tr_pttoplot_imp_msg[1]) # Management of the new vertices to transform into plots def tool_transfo_pt_to_plot(self): if self.rfu and self.rfu.layers[0]: # Set the layer l_vertex current self.iface.setActiveLayer(self.rfu.l_vertex) self.project.layerTreeRoot().findLayer( self.rfu.l_vertex.id()).setItemVisibilityChecked(True) self.canvas.refresh() # Check the editable mode if not self.rfu.l_vertex.isEditable(): self.rfu.l_vertex.startEditing() self.tr_pt_to_plot = TransfoPtToPlot( self.canvas, self.project, self.rfu.layers[0], self.rfu.layers[1], ) # # Modal window # self.tr_pt_to_plot.setWindowModality(Qt.ApplicationModal) self.tr_pt_to_plot.dlg_show() else: QMessageBox.information(self.iface.mainWindow(), tr_pttoplot_imp_msg[0], tr_pttoplot_imp_msg[1]) # Let the user choose a point to show the point plots def tool_select_pt_to_plot(self, type_fnc): self.plot_fnc_mode = type_fnc if self.conn and self.rfu and self.rfu.zone: # Prompt message self.iface.messageBar().pushMessage(plot_dif_txt[type_fnc][0], plot_dif_txt[type_fnc][1], Qgis.Info, duration=10) # Pointer to choose the vertex # Set the layer l_vertex current self.iface.setActiveLayer(self.rfu.l_vertex) self.project.layerTreeRoot().findLayer( self.rfu.l_vertex.id()).setItemVisibilityChecked(True) self.canvas.refresh() self.identify_pttoplot = QgsMapToolIdentifyFeature( self.canvas, self.rfu.l_vertex) self.identify_pttoplot.setCursor(QCursor(Qt.WhatsThisCursor)) self.identify_pttoplot.featureIdentified.connect( self.pt_to_plot_identified) self.canvas.setMapTool(self.identify_pttoplot) # Prepare and show the point plots dlg def pt_to_plot_identified(self, pt_feat): # Select the point self.rfu.l_vertex.selectByIds([pt_feat.id()]) id_node = pt_feat["@id_noeud"] # Check the selected point is a RFU vertex if id_node: resp_plots = None # Get the pt plots infos resp = self.conn.get_ptplots(id_node, self.rfu.zone) resp_plots = resp.read() tree = ElementTree.fromstring(resp_plots) if resp.code != 200: # Catch the error specified by the API elt_err = tree.find(r"./log") if elt_err.text: msg = elt_err.text else: # Error returned by the server (all other cases) msg = str(resp_plots) # Display the error in a message box return QMessageBox.warning(self.iface.mainWindow(), msg_obt_det_imp, msg) else: ptplot = tree.find(r"./sommet/determination") # Case of no plots if 'Message' in ptplot.attrib: msg = ptplot.attrib["Message"] QMessageBox.warning(self.iface.mainWindow(), msg_obt_det_imp, msg) else: # DEBUG # urlresp_to_file(resp_plots) # Prepare and show the dlg self.show_ptplots = ShowPtPlots(self.conn, self.rfu.zone, resp_plots, self.plot_fnc_mode, self.iface.mainWindow()) # Modal window self.show_ptplots.setWindowModality(Qt.ApplicationModal) self.show_ptplots.ptplotsNwPtSelect.connect( partial(self.tool_select_pt_to_plot, "info")) self.show_ptplots.plots_show() # Case of selected point is not a RFU vertex else: QMessageBox.warning(self.iface.mainWindow(), plot_notrfusel_msg[0], plot_notrfusel_msg[1]) # Lets appear the show capabilities dlg def tool_show_capabilities(self): resp_mycap = None resp_cap = None # Get C1 capabilities if self.conn: resp = self.conn.get_my_capabilities() resp_mycap = resp.read() if resp.code != 200: # Catch the error specified by the API tree = ElementTree.fromstring(resp_mycap) elt_err = tree.find(r"./log") if elt_err.text: msg = elt_err.text else: # Error returned by the server (all other cases).. msg = str(resp_mycap) # Display the error in a message box return QMessageBox.warning(self.iface.mainWindow(), msg_obt_cap_imp, msg) if self.rfu and self.rfu.zone: resp = self.conn.get_capabilities(self.rfu.zone) resp_cap = resp.read() # DEBUG: Export response as a text file # urlresp_to_file(resp_ap) if resp.code != 200: # Catch the error specified by the API tree = ElementTree.fromstring(resp_cap) elt_err = tree.find(r"./log") if elt_err.text: msg = elt_err.text else: # Error returned by the server (all other cases) msg = str(resp_cap) # Display the error in a message box return QMessageBox.warning(self.iface.mainWindow(), msg_obt_cap_imp, msg) # Prepare and show the dlg self.show_capa = ShowCapabilities(resp_cap, resp_mycap) self.show_capa.show() else: # No connection: alert message return QMessageBox.warning(self.iface.mainWindow(), msg_obt_cap_imp, msg_obt_cap_ident) # Allow (or disallow) creation and import def allow_creation(self, state): self.action_vtx_creator.setEnabled(state) self.action_edge_creator.setEnabled(state) self.action_import_csv2rfu.setEnabled(state) self.action_import_dxf2rfu.setEnabled(state) self.action_cut_oldlimit.setEnabled(state) self.action_transfo_pt_to_plot.setEnabled(state) self.action_del_ptplot.setEnabled(state) self.action_show_ptplots.setEnabled(state)
class CutOldLimit(QDialog, gui_dlg_cut_oldlimit): def __init__(self, canvas, project, l_vertex, l_edge, parent=None): super(CutOldLimit, self).__init__(parent) self.setupUi(self) self.canvas = canvas self.project = project self.l_edge = l_edge self.l_vertex = l_vertex self.parent = parent self.sel_nw_vtx = None self.resize_dlg = ResizeDlg(self, "dlg_cut_oldlimit") self.resize_params = self.resize_dlg.load_dlgresize() self.resize_on = self.resize_params["dlg_cut_oldlimit"] self.valid_btn.clicked.connect(self.close) self.resize_btn.clicked.connect(self.resize_dlg.dlg_ch_resize) self.sel_oldlim_btn.clicked.connect(self.sel_oldlim) self.sel_nwvtx_btn.clicked.connect(self.sel_nwvtx) self.validop_btn.clicked.connect(self.validop) # Delete Widget on close event self.setAttribute(Qt.WA_DeleteOnClose) # Let the user select the RFU old limit to cut def sel_oldlim(self): # Selection in the canvas self.hide() self.l_edge.removeSelection() self.identify_oldlim = QgsMapToolIdentifyFeature( self.canvas, self.l_edge) self.identify_oldlim.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_oldlim.featureIdentified.connect(self.oldlim_identified) self.canvas.setMapTool(self.identify_oldlim) # Let the user select the new vertices used to cut the old lmit def sel_nwvtx(self): # Selection in the canvas self.hide() self.identify_nwvtx = MultiSelNwVtxTool(self.parent, self.canvas, self.l_vertex) # self.identify_nwvtx.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_nwvtx.selected_feats.connect(self.nwvtx_identified) self.canvas.setMapTool(self.identify_nwvtx) # Check of the limit after selection def oldlim_identified(self, feat): self.l_edge.selectByIds([feat.id()]) self.canvas.unsetMapTool(self.identify_oldlim) # Check if the limit selected is an old RFU limit if feat[r"@id_arc"]: self.show() else: QMessageBox.warning(self, cutlim_notoldlim_msg[0], cutlim_notoldlim_msg[1]) self.l_edge.removeSelection() self.sel_oldlim() # Terminate the vertices selection def nwvtx_identified(self, lyr, feats): self.canvas.unsetMapTool(self.identify_nwvtx) self.show() # Cut operation def validop(self): self.hide() # Transformations to obtain the WGS84 or the CC coordinates coords_tr_wgs, coords_tr_cc = crs_trans_params(self.canvas, self.project) # Message if no limit selected if len(self.l_edge.selectedFeatures()) == 0: QMessageBox.information(self, cutlim_nolim_msg[0], cutlim_nolim_msg[1]) self.show() # Message if more than one limit selected elif len(self.l_edge.selectedFeatures()) > 1: QMessageBox.information(self, cutlim_toomuchlim_msg[0], cutlim_toomuchlim_msg[1]) self.l_edge.removeSelection() self.show() # Message if no vertex selected elif len(self.l_vertex.selectedFeatures()) == 0: QMessageBox.information(self, cutlim_nonwvtx_msg[0], cutlim_nonwvtx_msg[1]) self.show() # Do the job else: oldlim = self.l_edge.selectedFeatures()[0] # Find the att values lim_delim_pub = oldlim["lim_delimitation_publique"] lim_typologie_nature = oldlim["lim_typologie_nature"] oldlim_geom = oldlim.geometry() oldlim_geom_pl = oldlim_geom.asPolyline() start_lim_pt = oldlim_geom_pl[0] end_lim_pt = oldlim_geom_pl[-1] nw_pt_lst = [] # Manage each new vertex for nwpt in self.l_vertex.selectedFeatures(): # Find the creator ge_createur = nwpt["som_ge_createur"] nwpt_geom = nwpt.geometry() nwpt_geom_pt = nwpt_geom.asPoint() nw_pt_onlim = oldlim_geom.nearestPoint(nwpt_geom) dist_to_lim = dist_2_pts( coords_tr_cc.transform(nwpt_geom_pt), coords_tr_cc.transform(nw_pt_onlim.asPoint())) dist_pr_st = dist_2_pts( coords_tr_cc.transform(start_lim_pt), coords_tr_cc.transform(nw_pt_onlim.asPoint())) dist_pr_en = dist_2_pts( coords_tr_cc.transform(end_lim_pt), coords_tr_cc.transform(nw_pt_onlim.asPoint())) # Check if the new vertex is out of the old limit if dist_pr_en == 0 or dist_pr_st == 0: QMessageBox.information( self, cutlim_vtxout_msg[0], cutlim_vtxout_msg[1].format(nwpt.id())) else: # Create the list of new points to use for the new lmits nw_pt_lst.append( [dist_pr_st, nwpt.id(), dist_to_lim, nwpt_geom_pt]) # Sot the list of new points by their distance to the start vertex nw_pt_lst.sort() msg = "" if len(nw_pt_lst) > 0: # Create a message showing the distances, and asking to continue for nw_pt_info in nw_pt_lst: msg += msg_dist.format(nw_pt_info[1], float(nw_pt_info[2])) q_ok = QMessageBox.question(self, cutlim_vtxdist_msg[0], cutlim_vtxdist_msg[1].format(msg), QMessageBox.Yes | QMessageBox.No) # The user continues if q_ok == QMessageBox.Yes: for id, pt in enumerate(nw_pt_lst): end_vtx = pt[3] if id == 0: st_vtx = start_lim_pt line = QgsGeometry.fromPolylineXY([st_vtx, end_vtx]) st_vtx = pt[3] nw_attvals = [ NULL, NULL, ge_createur, lim_delim_pub, lim_typologie_nature ] # Create the feature create_nw_feat(self.l_edge, line, nw_attvals) # Case of the last limit to create if id == (len(nw_pt_lst) - 1): line = QgsGeometry.fromPolylineXY( [end_vtx, end_lim_pt]) create_nw_feat(self.l_edge, line, nw_attvals) self.l_edge.deleteFeature(oldlim.id()) self.l_edge.removeSelection() self.l_vertex.removeSelection() QMessageBox.information(self, cutlim_end_msg[0], cutlim_end_msg[1]) else: self.show() # No new limit to create else: QMessageBox.information(self, cutlim_noncre_msg[0], cutlim_noncre_msg[1]) self.show() def closeEvent(self, event): self.l_vertex.removeSelection() self.l_edge.removeSelection() self.close()
class AssociateExtAddressWizard(QWizard, WIZARD_UI): def __init__(self, iface, db, qgis_utils, parent=None): QWizard.__init__(self, parent) self.setupUi(self) self.iface = iface self.log = QgsApplication.messageLog() self._db = db self.qgis_utils = qgis_utils self.canvas = self.iface.mapCanvas() self.maptool = self.canvas.mapTool() self.maptool_identify = None self.help_strings = HelpStrings() self.translatable_config_strings = TranslatableConfigStrings() self._extaddress_layer = None self._plot_layer = None self._building_layer = None self._building_unit_layer = None self._current_layer = None self._feature_tid = None self.restore_settings() self.rad_to_plot.toggled.connect(self.adjust_page_1_controls) self.rad_to_building.toggled.connect(self.adjust_page_1_controls) self.rad_to_building_unit.toggled.connect(self.adjust_page_1_controls) self.adjust_page_1_controls() self.button(QWizard.NextButton).clicked.connect(self.prepare_selection) self.button(QWizard.FinishButton).clicked.connect(self.finished_dialog) self.button(QWizard.HelpButton).clicked.connect(self.show_help) self.mMapLayerComboBox.setFilters(QgsMapLayerProxyModel.PolygonLayer) self.bar = QgsMessageBar() self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.setLayout(QGridLayout()) self.layout().addWidget(self.bar, 0, 0, Qt.AlignTop) def adjust_page_1_controls(self): self.cbo_mapping.clear() self.cbo_mapping.addItem("") self.cbo_mapping.addItems( self.qgis_utils.get_field_mappings_file_names(EXTADDRESS_TABLE)) if self.rad_refactor.isChecked(): self.lbl_refactor_source.setEnabled(True) self.mMapLayerComboBox.setEnabled(True) self.lbl_field_mapping.setEnabled(True) self.cbo_mapping.setEnabled(True) disable_next_wizard(self) FinishButton_text = QCoreApplication.translate( "AssociateExtAddressWizard", "Import") self.txt_help_page_1.setHtml( self.help_strings.get_refactor_help_string( EXTADDRESS_TABLE, True)) self.wizardPage1.setFinalPage(True) self.wizardPage1.setButtonText( QWizard.FinishButton, QCoreApplication.translate("AssociateExtAddressWizard", FinishButton_text)) elif self.rad_to_plot.isChecked(): self.lbl_refactor_source.setEnabled(False) self.mMapLayerComboBox.setEnabled(False) self.lbl_field_mapping.setEnabled(False) self.cbo_mapping.setEnabled(False) self.wizardPage1.setFinalPage(False) enable_next_wizard(self) FinishButton_text = QCoreApplication.translate( "AssociateExtAddressWizard", "Associate Plot ExtAddress") self.txt_help_page_1.setHtml( self.help_strings. WIZ_ASSOCIATE_EXTADDRESS_CADASTRE_PAGE_1_OPTION_1) elif self.rad_to_building.isChecked(): self.lbl_refactor_source.setEnabled(False) self.mMapLayerComboBox.setEnabled(False) self.lbl_field_mapping.setEnabled(False) self.cbo_mapping.setEnabled(False) self.wizardPage1.setFinalPage(False) enable_next_wizard(self) FinishButton_text = QCoreApplication.translate( "AssociateExtAddressWizard", "Associate Building ExtAddress") self.txt_help_page_1.setHtml( self.help_strings. WIZ_ASSOCIATE_EXTADDRESS_CADASTRE_PAGE_1_OPTION_2) else: #self.rad_to_building_unit.isChecked(): self.lbl_refactor_source.setEnabled(False) self.mMapLayerComboBox.setEnabled(False) self.lbl_field_mapping.setEnabled(False) self.cbo_mapping.setEnabled(False) self.wizardPage1.setFinalPage(False) enable_next_wizard(self) FinishButton_text = QCoreApplication.translate( "AssociateExtAddressWizard", "Associate Building Unit ExtAddress") self.txt_help_page_1.setHtml( self.help_strings. WIZ_ASSOCIATE_EXTADDRESS_CADASTRE_PAGE_1_OPTION_3) self.wizardPage2.setButtonText( QWizard.FinishButton, QCoreApplication.translate('AssociateExtAddressWizard', FinishButton_text)) def prepare_selection(self): self.button(self.FinishButton).setDisabled(True) if self.rad_to_plot.isChecked(): self.btn_select.setText( QCoreApplication.translate("AssociateExtAddressWizard", "Select Plot")) self.txt_help_page_2.setHtml( self.help_strings. WIZ_ASSOCIATE_EXTADDRESS_CADASTRE_PAGE_2_OPTION_1) # Load layers res_layers = self.qgis_utils.get_layers(self._db, { EXTADDRESS_TABLE: { 'name': EXTADDRESS_TABLE, 'geometry': QgsWkbTypes.PointGeometry }, PLOT_TABLE: { 'name': PLOT_TABLE, 'geometry': QgsWkbTypes.PolygonGeometry } }, load=True) self._extaddress_layer = res_layers[EXTADDRESS_TABLE] self._plot_layer = res_layers[PLOT_TABLE] self._current_layer = self._plot_layer elif self.rad_to_building.isChecked(): self.btn_select.setText( QCoreApplication.translate("AssociateExtAddressWizard", "Select Building")) self.txt_help_page_2.setHtml( self.help_strings. WIZ_ASSOCIATE_EXTADDRESS_CADASTRE_PAGE_2_OPTION_2) # Load layers res_layers = self.qgis_utils.get_layers(self._db, { EXTADDRESS_TABLE: { 'name': EXTADDRESS_TABLE, 'geometry': QgsWkbTypes.PointGeometry }, BUILDING_TABLE: { 'name': BUILDING_TABLE, 'geometry': QgsWkbTypes.PolygonGeometry } }, load=True) self._extaddress_layer = res_layers[EXTADDRESS_TABLE] self._building_layer = res_layers[BUILDING_TABLE] self._current_layer = self._building_layer else: #self.rad_to_building_unit.isChecked(): self.btn_select.setText( QCoreApplication.translate("AssociateExtAddressWizard", "Select Building Unit")) self.txt_help_page_2.setHtml( self.help_strings. WIZ_ASSOCIATE_EXTADDRESS_CADASTRE_PAGE_2_OPTION_3) # Load layers res_layers = self.qgis_utils.get_layers(self._db, { EXTADDRESS_TABLE: { 'name': EXTADDRESS_TABLE, 'geometry': QgsWkbTypes.PointGeometry }, BUILDING_UNIT_TABLE: { 'name': BUILDING_UNIT_TABLE, 'geometry': QgsWkbTypes.PolygonGeometry } }, load=True) self._extaddress_layer = res_layers[EXTADDRESS_TABLE] self._building_unit_layer = res_layers[BUILDING_UNIT_TABLE] self._current_layer = self._building_unit_layer self.iface.setActiveLayer(self._current_layer) self.check_selected_features() self.btn_select.clicked.connect(self.select_feature) self.btn_select_by_expression.clicked.connect( self.select_feature_by_expression) def check_selected_features(self): self.bar.clearWidgets() if self._current_layer.selectedFeatureCount() == 1: self.lbl_selected.setText( QCoreApplication.translate("AssociateExtAddressWizard", "1 Feature Selected")) self.button(self.FinishButton).setDisabled(False) self._feature_tid = self._current_layer.selectedFeatures( )[0][ID_FIELD] self.canvas.zoomToSelected(self._current_layer) elif self._current_layer.selectedFeatureCount() > 1: self.show_message( QCoreApplication.translate("AssociateExtAddressWizard", "Please select just one feature"), Qgis.Warning) self.lbl_selected.setText( QCoreApplication.translate( "AssociateExtAddressWizard", "{} Feature(s) Selected".format( self._current_layer.selectedFeatureCount()))) self.button(self.FinishButton).setDisabled(True) else: self.lbl_selected.setText( QCoreApplication.translate("AssociateExtAddressWizard", "0 Features Selected")) self.button(self.FinishButton).setDisabled(True) def select_feature_by_expression(self): Dlg_expression_selection = QgsExpressionSelectionDialog( self._current_layer) self._current_layer.selectionChanged.connect( self.check_selected_features) Dlg_expression_selection.exec() self._current_layer.selectionChanged.disconnect( self.check_selected_features) def select_feature(self): self.setVisible(False) # Make wizard disappear # Create maptool self.maptool_identify = QgsMapToolIdentifyFeature(self.canvas) self.maptool_identify.setLayer(self._current_layer) cursor = QCursor() cursor.setShape(Qt.CrossCursor) self.maptool_identify.setCursor(cursor) self.canvas.setMapTool(self.maptool_identify) self.maptool_identify.featureIdentified.connect(self.get_feature_id) # TODO: Take into account that a user can select another tool def get_feature_id(self, feature): self.setVisible(True) # Make wizard appear if feature: self.lbl_selected.setText( QCoreApplication.translate("AssociateExtAddressWizard", "1 Feature Selected")) self._current_layer.selectByIds([feature.id()]) self.canvas.setMapTool(self.maptool) self.check_selected_features() self.maptool_identify.featureIdentified.disconnect(self.get_feature_id) self.log.logMessage( "Spatial Unit's featureIdentified SIGNAL disconnected", PLUGIN_NAME, Qgis.Info) def finished_dialog(self): self.save_settings() if self.rad_refactor.isChecked(): if self.mMapLayerComboBox.currentLayer() is not None: field_mapping = self.cbo_mapping.currentText() res_etl_model = self.qgis_utils.show_etl_model( self._db, self.mMapLayerComboBox.currentLayer(), EXTADDRESS_TABLE, field_mapping=field_mapping) if res_etl_model: if field_mapping: self.qgis_utils.delete_old_field_mapping(field_mapping) self.qgis_utils.save_field_mapping(EXTADDRESS_TABLE) else: self.iface.messageBar().pushMessage( 'Asistente LADM_COL', QCoreApplication.translate( "AssociateExtAddressWizard", "Select a source layer to set the field mapping to '{}'." ).format(EXTADDRESS_TABLE), Qgis.Warning) else: self.prepare_extaddress_creation() def prepare_extaddress_creation(self): # Don't suppress (i.e., show) feature form form_config = self._extaddress_layer.editFormConfig() form_config.setSuppress(QgsEditFormConfig.SuppressOff) self._extaddress_layer.setEditFormConfig(form_config) self.edit_extaddress() def edit_extaddress(self): if self._current_layer.selectedFeatureCount() == 1: # Open Form self.iface.layerTreeView().setCurrentLayer(self._extaddress_layer) self._extaddress_layer.startEditing() self.iface.actionAddFeature().trigger() # Create connections to react when a feature is added to buffer and # when it gets stored into the DB self._extaddress_layer.featureAdded.connect( self.call_extaddress_commit) else: self.iface.messageBar().pushMessage( "Asistente LADM_COL", QCoreApplication.translate("AssociateExtAddressWizard", "Please select a feature"), Qgis.Warning) def call_extaddress_commit(self, fid): plot_field_idx = self._extaddress_layer.getFeature(fid).fieldNameIndex( EXTADDRESS_PLOT_FIELD) building_field_idx = self._extaddress_layer.getFeature( fid).fieldNameIndex(EXTADDRESS_BUILDING_FIELD) building_unit_field_idx = self._extaddress_layer.getFeature( fid).fieldNameIndex(EXTADDRESS_BUILDING_UNIT_FIELD) if self._current_layer.name() == PLOT_TABLE: self._extaddress_layer.changeAttributeValue( fid, plot_field_idx, self._feature_tid) elif self._current_layer.name() == BUILDING_TABLE: self._extaddress_layer.changeAttributeValue( fid, building_field_idx, self._feature_tid) else: #self._current_layer.name() == BUILDING_UNIT_TABLE: self._extaddress_layer.changeAttributeValue( fid, building_unit_field_idx, self._feature_tid) self._extaddress_layer.featureAdded.disconnect( self.call_extaddress_commit) self.log.logMessage("Extaddres's featureAdded SIGNAL disconnected", PLUGIN_NAME, Qgis.Info) res = self._extaddress_layer.commitChanges() self._current_layer.removeSelection() def show_message(self, message, level): self.bar.pushMessage(message, level, 0) def save_settings(self): settings = QSettings() load_data_type = 'refactor' if self.rad_to_plot.isChecked(): load_data_type = 'to_plot' elif self.rad_to_building.isChecked(): load_data_type = 'to_building' else: #self.rad_to_building_unit.isChecked(): load_data_type = 'to_building_unit' settings.setValue( 'Asistente-LADM_COL/wizards/ext_address_load_data_type', load_data_type) def restore_settings(self): settings = QSettings() load_data_type = settings.value( 'Asistente-LADM_COL/wizards/ext_address_load_data_type', 'to_plot') if load_data_type == 'refactor': self.rad_refactor.setChecked(True) elif load_data_type == 'to_plot': self.rad_to_plot.setChecked(True) elif load_data_type == 'to_building': self.rad_to_building.setChecked(True) else: #load_data_type == 'to_building_unit': self.rad_to_building_unit.setChecked(True) def show_help(self): self.qgis_utils.show_help("associate_ext_address")