示例#1
0
class Window(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(Window, self).__init__()
        self.setupUi(self)

        self.layers = []

        # ---------初始化图层和画布----------
        self.vl = QVBoxLayout(self.dockWidgetContents)
        self.layer_tree_view = QgsLayerTreeView(self)
        self.vl.addWidget(self.layer_tree_view)
        self.hl = QHBoxLayout(self.frame)
        self.mapCanvas = QgsMapCanvas(self.frame)
        self.hl.addWidget(self.mapCanvas)
        # ---------初始化图层和画布----------

        self.action_open.triggered.connect(self.action_open_triggered)

        # 建立桥梁
        self.model = QgsLayerTreeModel(QgsProject.instance().layerTreeRoot(), self)
        self.model.setFlag(QgsLayerTreeModel.AllowNodeRename)
        self.model.setFlag(QgsLayerTreeModel.AllowNodeReorder)
        self.model.setFlag(QgsLayerTreeModel.AllowNodeChangeVisibility)
        self.model.setFlag(QgsLayerTreeModel.ShowLegendAsTree)
        self.model.setAutoCollapseLegendNodes(10)
        self.layer_tree_view.setModel(self.model)
        self.layer_tree_bridge = QgsLayerTreeMapCanvasBridge(QgsProject.instance().layerTreeRoot(), self.mapCanvas)

        # 设置识别工具
        self.identifyTool = QgsMapToolIdentifyFeature(self.mapCanvas)
        # 发送识别的要素
        self.identifyTool.featureIdentified.connect(self.print_features)
        self.mapCanvas.setMapTool(self.identifyTool)

    def action_open_triggered(self):
        data_file, ext = QFileDialog.getOpenFileName(self, '打开', '', '所有文件(*)')
        if data_file:
            if data_file.endswith('.shp'):
                basename = os.path.splitext(os.path.basename(data_file))[0]
                layer = QgsVectorLayer(data_file, basename, "ogr")
                QgsProject.instance().addMapLayer(layer)
                self.layers.append(layer)
                self.mapCanvas.setExtent(layer.extent())
                self.mapCanvas.setLayers(self.layers)
                self.mapCanvas.refresh()
                self.layer_tree_view.setCurrentLayer(layer)

                # 设置需要识别的图层
                self.identifyTool.setLayer(layer)

            elif data_file.endswith('.qgz') or data_file.endswith('.qgs'):
                QgsProject.instance().read(data_file)
            else:
                print('error')

    def print_features(self, feature):
        print(feature.attributes())
        print(feature.fields())
        print(feature.geometry())
示例#2
0
class MapWindow(QMainWindow):
    """This class offers a canvas and tools to select polygons from a vector
        layer provided by the main app."""
        
    # signal emitted when polygons succesfully selected
    finished = pyqtSignal()
    
    def __init__(self):
        QMainWindow.__init__(self)
        #self.setWindowFlags(Qt.CustomizeWindowHint)
        #self.setWindowFlags(Qt.WindowMinMaxButtonsHint)
        
        # creating map canvas, which draws the maplayers
        # setting up features like canvas color
        self.canvas = QgsMapCanvas()
        self.canvas.setMinimumSize(550, 700)
        self.canvas.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        self.canvas.setCanvasColor(Qt.white)
        self.canvas.setSelectionColor(QColor(255,255,26,200))
        self.canvas.enableAntiAliasing(True)
        self.canvas.setParallelRenderingEnabled(True)

        # empty list for selected polygons
        self.selected_features = []
        
        # setting up label settings: object below houses all of them
        self.label_settings = QgsPalLayerSettings()
        
        # object for text settings
        text_format = QgsTextFormat()
        
        text_format.setFont(QFont("Helvetica", 12))
        text_format.setSize(7)
        
        # setting up a white buffer around the labels
        buffer_settings = QgsTextBufferSettings()
        buffer_settings.setEnabled(True)
        buffer_settings.setSize(0.65)
        buffer_settings.setColor(Qt.white)
        text_format.setBuffer(buffer_settings)
        
        # label settings:
        # fieldName = which field is shown as the label (currently Finnish name)
        # placement = labels can be placed differently in relation to one another
        #              - see documentation for details
        self.label_settings.setFormat(text_format)
        self.label_settings.fieldName = "namefin"
        self.label_settings.placement = 0
        self.label_settings.enabled = True
        
        # Qmainwindow requires a central widget. Canvas is placed
        self.setCentralWidget(self.canvas)
        
        # creating each desired action
        self.actionGet = QAction("Return selected and close", self)
        self.actionPan = QAction("Pan tool", self)
        self.actionSelect = QAction("Select tool", self)
        self.actionClear = QAction("Clear selection", self)
        self.actionCancel = QAction("Cancel and close", self)
        
        # these two function as on/off. the rest are clickable
        self.actionPan.setCheckable(True)
        self.actionSelect.setCheckable(True)
        
        # when actions are clicked, do corresponding function
        self.actionPan.triggered.connect(self.pan)
        self.actionSelect.triggered.connect(self.select)
        self.actionClear.triggered.connect(self.clearSelection)
        self.actionGet.triggered.connect(self.finishedSelection)
        self.actionCancel.triggered.connect(self.cancel)
        
        # toolbar at the top of the screen: houses actions as buttons
        # change order here to change their placement on window
        self.toolbar = self.addToolBar("Canvas actions")
        self.toolbar.setContextMenuPolicy(Qt.PreventContextMenu)
        self.toolbar.setMovable(False)
        self.toolbar.addAction(self.actionGet)
        self.toolbar.addAction(self.actionPan)
        self.toolbar.addAction(self.actionSelect)
        self.toolbar.addAction(self.actionClear)
        self.toolbar.addAction(self.actionCancel)

        # link actions to premade map tools
        self.toolPan = QgsMapToolPan(self.canvas)
        self.toolPan.setAction(self.actionPan)
        self.toolSelect = QgsMapToolIdentifyFeature(self.canvas)
        self.toolSelect.setAction(self.actionSelect)
        self.toolSelect.featureIdentified.connect(self.selectFeature)
        
        self.blocks_flag = False
        
        self.selection_rectangle = False
        
        # set select tool as default
        self.select()

    def pan(self):
        """Simply activates the tool"""
        self.canvas.setMapTool(self.toolPan)
        
    def select(self):
        self.canvas.setMapTool(self.toolSelect)
        
    def addLayer(self, layer):
        """Called when user click button on the main plugin: receives a vector
            layer, sets up labels & rendering parameters and shows the layer."""
        # empty output list in case function is called multiple times
        self.selected_features.clear()
        self.selection_rectangle = False
        
        # layer into a self variable
        self.layer = layer
        
        # add layer to project: required to show it on screen
        # False = do not show the layer on the legend listing nor draw on main canvas
        QgsProject.instance().addMapLayer(self.layer, False)
        
        # set up visual stuff
        self.layer.setLabelsEnabled(True)
        layer_labeling = QgsVectorLayerSimpleLabeling(self.label_settings)
        self.layer.setLabeling(layer_labeling)
        self.layer.renderer().symbol().setColor(QColor(220,220,220))
        
        # select tool needs a vector layer assigned to it
        self.toolSelect.setLayer(self.layer)
        self.canvas.setExtent(self.layer.extent())
        
        # set layer to canvas
        self.canvas.setLayers([self.layer])
        
        # show to user
        self.show()
        
    def addBlocksLayer(self, layer):
        self.selected_features.clear()
        self.blocks_flag = True
        
        self.layer = layer
        
        QgsProject.instance().addMapLayer(self.layer, False)
        
        self.layer.renderer().symbol().setColor(Qt.cyan)
        self.layer.renderer().symbol().setOpacity(0.30)
        
        # select tool needs a vector layer assigned to it
        self.toolSelect.setLayer(self.layer)
        self.canvas.setExtent(self.layer.extent())
        
        # set layer to canvas
        """
        url = ("https://vm0160.kaj.pouta.csc.fi/geoserver/ows?service=wfs&version=2.0.0"+ 
        "&request=GetFeature&typename=ogiir:maakuntajako_2018_4500k&pagingEnabled=true")
        self.bg_layer = QgsVectorLayer(url, "BACKGROUND-REMOVE", "WFS")
        """
        self.bg_layer = QgsRasterLayer("url=https://vm0160.kaj.pouta.csc.fi/ogiir_cache/wmts/1.0.0/" +
                       "WMTSCapabilities.xml&crs=EPSG:3067&dpiMode=7&format=image/"+
                       "png&layers=taustakartta&styles=default&tileMatrixSet=GRIDI-FIN", 
                       'GEOCUBES BG-LAYER - TEMPORARY', 'wms')

        if self.bg_layer.isValid():
            QgsProject.instance().addMapLayer(self.bg_layer, False)
            self.canvas.setLayers([self.layer, self.bg_layer])
        else:
            self.canvas.setLayers([self.layer])
        
        self.show()
        
        
    def selectFeature(self, feat):
        """Activated when user clicks something on screen. This returns the
            clicked feature. The function does 2 things:
            1. selects the feature on the map / deselects if already selected
            2. adds features to a list in the same format (name, id_code) as 
                they're stored in the 'Admin areas box' in the main file """
        idx  = feat.id()
        if self.blocks_flag:
            xmin = feat[0]
            ymax = feat[1]
            label = str(xmin) + "|" + str(ymax) 
        else:
            code = feat[1]
            name = feat[2]
            label = name + "|" + code
        
        if label in self.selected_features:
            self.layer.deselect(idx)
            self.selected_features.remove(label)
        else:
            self.layer.select(idx)
            self.selected_features.append(label)
            
    def clearSelection(self):
        """Clear map selection and list on button click"""
        self.layer.removeSelection()
        self.selected_features.clear()
        
    def finishedSelection(self):
        """Activated when user clicks 'return selection'. Closes window
            and emits signal to indicate the job is finished"""
        self.close()
        self.finished.emit()
        
    def cancel(self):
        """In case user changes their mind. Does the same as above, but doesn't
            emit signal."""
        self.close()
        
    def getSelection(self):
        """Returns list of selected features (polygons)"""
        return self.selected_features
    
    def getSelectionBbox(self):
        return self.selection_rectangle
        
    def closeEvent(self, event):
        """Activated anytime Mapwindow is closed either by buttons given or
            if the user finds some other way to close the window. Removes
            selection and deletes scrap maplayer."""
        self.selection_rectangle = self.layer.boundingBoxOfSelected()
        self.layer.removeSelection()
        QgsProject.instance().removeMapLayer(self.layer)
        try:
            QgsProject.instance().removeMapLayer(self.bg_layer)
        except Exception:
            pass
        self.blocks_flag = False
        QMainWindow.closeEvent(self, event)
示例#3
0
class LinkerDock(QDockWidget, Ui_linker, SettingDialog):
    def __init__(self, iface):
        # QGIS
        self.iface = iface
        self.settings = MySettings()
        self.linkRubber = QgsRubberBand(self.iface.mapCanvas())
        self.featureHighlight = None
        # Relation management
        self.relationManager = QgsProject.instance().relationManager()
        self.relationManager.changed.connect(self.loadRelations)
        self.relation = QgsRelation()
        self.referencingFeature = QgsFeature()
        self.relationWidgetWrapper = None
        self.editorContext = QgsAttributeEditorContext()
        self.editorContext.setVectorLayerTools(self.iface.vectorLayerTools())

        # GUI
        QDockWidget.__init__(self)
        self.setupUi(self)
        SettingDialog.__init__(self, MySettings(), False, True)
        self.drawButton.setChecked(self.settings.value("drawEnabled"))

        self.relationReferenceWidget.setAllowMapIdentification(True)
        self.relationReferenceWidget.setEmbedForm(False)

        self.mapTool = QgsMapToolIdentifyFeature(self.iface.mapCanvas())
        self.mapTool.setButton(self.identifyReferencingFeatureButton)

        # Connect signal/slot
        self.relationComboBox.currentIndexChanged.connect(self.currentRelationChanged)
        self.mapTool.featureIdentified.connect(self.setReferencingFeature)

        # load relations at start
        self.loadRelations()

    def showEvent(self, QShowEvent):
        self.drawLink()

    def closeEvent(self, e):
        self.iface.mapCanvas().unsetMapTool(self.mapTool)
        self.linkRubber.reset()
        self.deleteHighlight()
        self.deleteWrapper()
        self.disconnectLayer()

    def disconnectLayer(self):
        if self.relation.isValid():
            self.relation.referencingLayer().editingStarted.disconnect(self.relationEditableChanged)
            self.relation.referencingLayer().editingStopped.disconnect(self.relationEditableChanged)
            self.relation.referencingLayer().attributeValueChanged.disconnect(self.layerValueChangedOutside)

    def runForFeature(self, relationId, layer, feature):
        index = self.relationComboBox.findData(relationId)
        self.relationComboBox.setCurrentIndex(index)
        self.setReferencingFeature(feature)
        self.show()
        if not layer.isEditable():
            self.iface.messageBar().pushMessage("Link It", "Cannot set a new related feature since %s is not editable" % layer.name(), QgsMessageBar.WARNING, 4)
        else:
            self.relationReferenceWidget.mapIdentification()

    @pyqtSlot(name="on_identifyReferencingFeatureButton_clicked")
    def activateMapTool(self):
        self.iface.mapCanvas().setMapTool(self.mapTool)

    def deactivateMapTool(self):
        self.iface.mapCanvas().unsetMapTool(self.mapTool)

    def loadRelations(self):
        self.deleteWrapper()
        self.disconnectLayer()
        self.relation = QgsRelation()
        self.referencingFeature = QgsFeature()
        self.relationComboBox.currentIndexChanged.disconnect(self.currentRelationChanged)
        self.relationComboBox.clear()
        for relation in self.relationManager.referencedRelations():
            if relation.referencingLayer().hasGeometryType():
                self.relationComboBox.addItem(relation.name(), relation.id())
        self.relationComboBox.setCurrentIndex(-1)
        self.relationComboBox.currentIndexChanged.connect(self.currentRelationChanged)
        self.currentRelationChanged(-1)

    def currentRelationChanged(self, index):
        # disconnect previous relation
        if self.relation.isValid():
            try:
                self.relation.referencingLayer().editingStarted.disconnect(self.relationEditableChanged)
                self.relation.referencingLayer().editingStopped.disconnect(self.relationEditableChanged)
                self.relation.referencingLayer().attributeValueChanged.disconnect(self.layerValueChangedOutside)
            except TypeError:
                pass

        self.referencingFeatureLayout.setEnabled(index >= 0)
        relationId = self.relationComboBox.itemData(index)
        self.relation = self.relationManager.relation(relationId)
        self.mapTool.setLayer(self.relation.referencingLayer())
        self.setReferencingFeature()
        # connect
        if self.relation.isValid():
            self.relation.referencingLayer().editingStarted.connect(self.relationEditableChanged)
            self.relation.referencingLayer().editingStopped.connect(self.relationEditableChanged)
            self.relation.referencingLayer().attributeValueChanged.connect(self.layerValueChangedOutside)

    def setReferencingFeature(self, feature=QgsFeature()):
        self.deactivateMapTool()
        self.referencingFeature = QgsFeature(feature)
        self.deleteWrapper()

        # disable relation reference widget if no referencing feature
        self.referencedFeatureLayout.setEnabled(feature.isValid())

        # set line edit
        if not self.relation.isValid() or not feature.isValid():
            self.referencingFeatureLineEdit.clear()
            return
        self.referencingFeatureLineEdit.setText("%s" % feature.id())

        fieldIdx = self.referencingFieldIndex()
        widgetConfig = self.relation.referencingLayer().editorWidgetV2Config(fieldIdx)
        self.relationWidgetWrapper = QgsEditorWidgetRegistry.instance().create("RelationReference",
                                                                               self.relation.referencingLayer(),
                                                                               fieldIdx,
                                                                               widgetConfig,
                                                                               self.relationReferenceWidget,
                                                                               self,
                                                                               self.editorContext)

        self.relationWidgetWrapper.setEnabled(self.relation.referencingLayer().isEditable())
        self.relationWidgetWrapper.setValue(feature[fieldIdx])
        self.relationWidgetWrapper.valueChanged.connect(self.foreignKeyChanged)
        # override field definition to allow map identification
        self.relationReferenceWidget.setAllowMapIdentification(True)
        self.relationReferenceWidget.setEmbedForm(False)

        # update drawn link
        self.highlightReferencingFeature()
        self.drawLink()

    def deleteWrapper(self):
        if self.relationWidgetWrapper is not None:
            self.relationWidgetWrapper.valueChanged.disconnect(self.foreignKeyChanged)
            self.relationWidgetWrapper.setValue(None)
            del self.relationWidgetWrapper
            self.relationWidgetWrapper = None

    def foreignKeyChanged(self, newKey):
        if not self.relation.isValid() or not self.relation.referencingLayer().isEditable() or not self.referencingFeature.isValid():
            self.drawLink()
            return
        if not self.relation.referencingLayer().editBuffer().changeAttributeValue(self.referencingFeature.id(), self.referencingFieldIndex(), newKey):
            self.iface.messageBar().pushMessage("Link It", "Cannot change attribute value.", QgsMessageBar.CRITICAL)
        self.drawLink()

    def relationEditableChanged(self):
        if self.relationWidgetWrapper is not None:
            self.relationWidgetWrapper.setEnabled(self.relation.isValid() and self.relation.referencingLayer().isEditable())

    def layerValueChangedOutside(self, fid, fieldIdx, value):
        if not self.relation.isValid() or not self.referencingFeature.isValid() or self.relationWidgetWrapper is None:
            return
        # not the correct feature
        if fid != self.referencingFeature.id():
            return
        # not the correct field
        if fieldIdx != self.referencingFieldIndex():
            return
        # widget already has this value
        if value == self.relationWidgetWrapper.value():
            return
        self.relationWidgetWrapper.valueChanged.disconnect(self.foreignKeyChanged)
        self.relationWidgetWrapper.setValue(value)
        self.relationWidgetWrapper.valueChanged.connect(self.foreignKeyChanged)

    def referencingFieldIndex(self):
        if not self.relation.isValid():
            return -1
        fieldName = self.relation.fieldPairs().keys()[0]
        fieldIdx = self.relation.referencingLayer().fieldNameIndex(fieldName)
        return fieldIdx

    @pyqtSlot(bool, name="on_drawButton_toggled")
    def drawLink(self):
        self.settings.setValue("drawEnabled", self.drawButton.isChecked())
        self.linkRubber.reset()
        if not self.drawButton.isChecked() or not self.referencingFeature.isValid() or not self.relation.isValid():
            return

        referencedFeature = self.relationReferenceWidget.referencedFeature()
        if not referencedFeature.isValid():
            return

        p1 = self.centroid(self.relation.referencedLayer(), referencedFeature)
        p2 = self.centroid(self.relation.referencingLayer(), self.referencingFeature)
        geom = arc(p1, p2)

        self.linkRubber.setToGeometry(geom, None)
        self.linkRubber.setWidth(self.settings.value("rubberWidth"))
        self.linkRubber.setColor(self.settings.value("rubberColor"))
        self.linkRubber.setLineStyle(Qt.DashLine)

    def centroid(self, layer, feature):
        geom = feature.geometry()
        if geom.type() == QGis.Line:
            geom = geom.interpolate(geom.length()/2)
        else:
            geom = geom.centroid()
        return self.iface.mapCanvas().mapSettings().layerToMapCoordinates(layer, geom.asPoint())

    @pyqtSlot(name="on_highlightReferencingFeatureButton_clicked")
    def highlightReferencingFeature(self):
        self.deleteHighlight()
        if not self.relation.isValid() or not self.referencingFeature.isValid():
            return
        
        self.featureHighlight = QgsHighlight(self.iface.mapCanvas(), self.referencingFeature.geometry(), self.relation.referencingLayer())
        settings = QSettings()
        color = QColor( settings.value("/Map/highlight/color", QGis.DEFAULT_HIGHLIGHT_COLOR.name()))
        alpha = int(settings.value("/Map/highlight/colorAlpha", QGis.DEFAULT_HIGHLIGHT_COLOR.alpha()))
        bbuffer = float(settings.value("/Map/highlight/buffer", QGis.DEFAULT_HIGHLIGHT_BUFFER_MM))
        minWidth = float(settings.value("/Map/highlight/minWidth", QGis.DEFAULT_HIGHLIGHT_MIN_WIDTH_MM))
        
        self.featureHighlight.setColor(color)
        color.setAlpha(alpha)
        self.featureHighlight.setFillColor(color)
        self.featureHighlight.setBuffer(bbuffer)
        self.featureHighlight.setMinWidth(minWidth)
        self.featureHighlight.show()

        timer = QTimer(self)
        timer.setSingleShot(True)
        timer.timeout.connect(self.deleteHighlight)
        timer.start(3000)

    def deleteHighlight(self):
        if self.featureHighlight:
            del self.featureHighlight
        self.featureHighlight = None
示例#4
0
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)
示例#5
0
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 FeatureSelectorWidget(QWidget):
    featureIdentified = pyqtSignal(QgsFeature)

    def __init__(self, parent):
        QWidget.__init__(self, parent)

        editLayout = QHBoxLayout()
        editLayout.setContentsMargins(0, 0, 0, 0)
        editLayout.setSpacing(2)
        self.setLayout(editLayout)

        self.lineEdit = QLineEdit(self)
        self.lineEdit.setReadOnly(True)
        editLayout.addWidget(self.lineEdit)
        
        self.highlightFeatureButton = QToolButton(self)
        self.highlightFeatureButton.setPopupMode(QToolButton.MenuButtonPopup)
        self.highlightFeatureAction = QAction(QgsApplication.getThemeIcon("/mActionHighlightFeature.svg"), "Highlight feature", self)
        self.scaleHighlightFeatureAction = QAction(QgsApplication.getThemeIcon("/mActionScaleHighlightFeature.svg"), "Scale and highlight feature", self)
        self.panHighlightFeatureAction = QAction(QgsApplication.getThemeIcon("/mActionPanHighlightFeature.svg"), "Pan and highlight feature", self)
        self.highlightFeatureButton.addAction(self.highlightFeatureAction)
        self.highlightFeatureButton.addAction(self.scaleHighlightFeatureAction)
        self.highlightFeatureButton.addAction(self.panHighlightFeatureAction)
        self.highlightFeatureButton.setDefaultAction(self.highlightFeatureAction)
        editLayout.addWidget(self.highlightFeatureButton)

        self.mapIdentificationButton = QToolButton(self)
        self.mapIdentificationButton.setIcon(QgsApplication.getThemeIcon("/mActionMapIdentification.svg"))
        self.mapIdentificationButton.setText("Select on map")
        self.mapIdentificationButton.setCheckable(True)
        editLayout.addWidget(self.mapIdentificationButton)

        self.mapIdentificationButton.clicked.connect(self.mapIdentification)
        self.highlightFeatureButton.triggered.connect(self.highlightActionTriggered)

        self.layer = None
        self.mapTool = None
        self.canvas = None
        self.windowWidget = None
        self.highlight = None
        self.feature = QgsFeature()

    def setCanvas(self, mapCanvas):
        self.mapTool = QgsMapToolIdentifyFeature(mapCanvas)
        self.mapTool.setButton(self.mapIdentificationButton)
        self.canvas = mapCanvas

    def setLayer(self, layer):
        self.layer = layer

    def setFeature(self, feature, canvasExtent = CanvasExtent.Fixed):
        self.lineEdit.clear()
        self.feature = feature

        if not self.feature.isValid() or self.layer is None:
            return

        featureTitle = feature.attribute(self.layer.displayField())
        if featureTitle == '':
            featureTitle = feature.id()
        self.lineEdit.setText(str(featureTitle))
        self.highlightFeature(canvasExtent)


    def clear(self):
        self.feature = QgsFeature()
        self.lineEdit.clear()

    def mapIdentification(self):
        if self.layer is None or self.mapTool is None or self.canvas is None:
            return

        self.mapTool.setLayer(self.layer)
        self.canvas.setMapTool(self.mapTool)

        self.windowWidget = QWidget.window(self)
        self.canvas.window().raise_()
        self.canvas.activateWindow()
        self.canvas.setFocus()

        self.mapTool.featureIdentified.connect(self.mapToolFeatureIdentified)
        self.mapTool.deactivated.connect(self.mapToolDeactivated)

    def mapToolFeatureIdentified(self, feature):
        feature = QgsFeature(feature)
        self.featureIdentified.emit(feature)
        self.unsetMapTool()
        self.setFeature(feature)

    def mapToolDeactivated(self):
        if self.windowWidget is not None:
            self.windowWidget.raise_()
            self.windowWidget.activateWindow()

    def highlightFeature(self, canvasExtent = CanvasExtent.Fixed):
        if self.canvas is None or not self.feature.isValid():
            return

        geom = self.feature.geometry()

        if geom is None:
            return
  
        if canvasExtent == CanvasExtent.Scale:
            featBBox = geom.boundingBox()
            featBBox = self.canvas.mapSettings().layerToMapCoordinates(self.layer, featBBox)
            extent = self.canvas.extent()
            if not extent.contains(featBBox):
                extent.combineExtentWith(featBBox)
                extent.scale(1.1)
                self.canvas.setExtent(extent)
                self.canvas.refresh()
            
        elif canvasExtent == CanvasExtent.Pan:
            centroid = geom.centroid()
            center = centroid.asPoint()

            center = self.canvas.mapSettings().layerToMapCoordinates(self.layer, center)
            self.canvas.zoomByFactor(1.0, center)  # refresh is done in this method

        # highlight
        self.delete_highlight()
        self.highlight = QgsHighlight(self.canvas, geom, self.layer)

        settings = QSettings()
        color = QColor(settings.value("/Map/highlight/color", QGis.DEFAULT_HIGHLIGHT_COLOR.name()))
        alpha = int(settings.value("/Map/highlight/colorAlpha", QGis.DEFAULT_HIGHLIGHT_COLOR.alpha()))
        buffer = 2*float(settings.value("/Map/highlight/buffer", QGis.DEFAULT_HIGHLIGHT_BUFFER_MM))
        min_width = 2*float(settings.value("/Map/highlight/min_width", QGis.DEFAULT_HIGHLIGHT_MIN_WIDTH_MM))

        self.highlight.setColor(color)  # sets also fill with default alpha
        color.setAlpha(alpha)
        self.highlight.setFillColor(color)  # sets fill with alpha
        self.highlight.setBuffer(buffer)
        self.highlight.setMinWidth(min_width)
        self.highlight.setWidth(4.0)
        self.highlight.show()
        
        self.timer = QTimer(self)
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(self.delete_highlight)
        self.timer.start(3000)

    def delete_highlight(self):
        if self.highlight is not None:
            self.highlight.hide()
            del self.highlight
            self.highlight = None

    def unsetMapTool(self):
        if self.canvas is not None and self.mapTool is not None:
            # this will call mapToolDeactivated
            self.canvas.unsetMapTool(self.mapTool)

    def highlightActionTriggered(self, action):
        self.highlightFeatureButton.setDefaultAction(action)

        if action == self.highlightFeatureAction:
            self.highlightFeature()

        elif action == self.scaleHighlightFeatureAction:
            self.highlightFeature(CanvasExtent.Scale)

        elif action == self.panHighlightFeatureAction:
            self.highlightFeature(CanvasExtent.Pan)
示例#7
0
class LinkerDock(QDockWidget, Ui_linker, SettingDialog):
    def __init__(self, iface):
        # QGIS
        self.iface = iface
        self.settings = MySettings()
        self.linkRubber = QgsRubberBand(self.iface.mapCanvas())
        self.featureHighlight = None
        # Relation management
        self.relationManager = QgsProject.instance().relationManager()
        self.relationManager.changed.connect(self.loadRelations)
        self.relation = QgsRelation()
        self.referencingFeature = QgsFeature()
        self.relationWidgetWrapper = None
        self.editorContext = QgsAttributeEditorContext()
        self.editorContext.setVectorLayerTools(self.iface.vectorLayerTools())

        # GUI
        QDockWidget.__init__(self)
        self.setupUi(self)
        SettingDialog.__init__(self, MySettings(), False, True)
        self.drawButton.setChecked(self.settings.value("drawEnabled"))

        self.relationReferenceWidget.setAllowMapIdentification(True)
        self.relationReferenceWidget.setEmbedForm(False)

        self.mapTool = QgsMapToolIdentifyFeature(self.iface.mapCanvas())
        self.mapTool.setButton(self.identifyReferencingFeatureButton)

        # Connect signal/slot
        self.relationComboBox.currentIndexChanged.connect(
            self.currentRelationChanged)
        self.mapTool.featureIdentified.connect(self.setReferencingFeature)

        # load relations at start
        self.loadRelations()

    def showEvent(self, QShowEvent):
        self.drawLink()

    def closeEvent(self, e):
        self.iface.mapCanvas().unsetMapTool(self.mapTool)
        self.linkRubber.reset()
        self.deleteHighlight()
        self.deleteWrapper()
        self.disconnectLayer()

    def disconnectLayer(self):
        if self.relation.isValid():
            self.relation.referencingLayer().editingStarted.disconnect(
                self.relationEditableChanged)
            self.relation.referencingLayer().editingStopped.disconnect(
                self.relationEditableChanged)
            self.relation.referencingLayer().attributeValueChanged.disconnect(
                self.layerValueChangedOutside)

    def runForFeature(self, relationId, layer, feature):
        index = self.relationComboBox.findData(relationId)
        self.relationComboBox.setCurrentIndex(index)
        self.setReferencingFeature(feature)
        self.show()
        if not layer.isEditable():
            self.iface.messageBar().pushMessage(
                "Link It",
                "Cannot set a new related feature since %s is not editable" %
                layer.name(), QgsMessageBar.WARNING, 4)
        else:
            self.relationReferenceWidget.mapIdentification()

    @pyqtSlot(name="on_identifyReferencingFeatureButton_clicked")
    def activateMapTool(self):
        self.iface.mapCanvas().setMapTool(self.mapTool)

    def deactivateMapTool(self):
        self.iface.mapCanvas().unsetMapTool(self.mapTool)

    def loadRelations(self):
        self.deleteWrapper()
        self.disconnectLayer()
        self.relation = QgsRelation()
        self.referencingFeature = QgsFeature()
        self.relationComboBox.currentIndexChanged.disconnect(
            self.currentRelationChanged)
        self.relationComboBox.clear()
        for relation in self.relationManager.referencedRelations():
            if relation.referencingLayer().hasGeometryType():
                self.relationComboBox.addItem(relation.name(), relation.id())
        self.relationComboBox.setCurrentIndex(-1)
        self.relationComboBox.currentIndexChanged.connect(
            self.currentRelationChanged)
        self.currentRelationChanged(-1)

    def currentRelationChanged(self, index):
        # disconnect previous relation
        if self.relation.isValid():
            try:
                self.relation.referencingLayer().editingStarted.disconnect(
                    self.relationEditableChanged)
                self.relation.referencingLayer().editingStopped.disconnect(
                    self.relationEditableChanged)
                self.relation.referencingLayer(
                ).attributeValueChanged.disconnect(
                    self.layerValueChangedOutside)
            except TypeError:
                pass

        self.referencingFeatureLayout.setEnabled(index >= 0)
        relationId = self.relationComboBox.itemData(index)
        self.relation = self.relationManager.relation(relationId)
        self.mapTool.setLayer(self.relation.referencingLayer())
        self.setReferencingFeature()
        # connect
        if self.relation.isValid():
            self.relation.referencingLayer().editingStarted.connect(
                self.relationEditableChanged)
            self.relation.referencingLayer().editingStopped.connect(
                self.relationEditableChanged)
            self.relation.referencingLayer().attributeValueChanged.connect(
                self.layerValueChangedOutside)

    def setReferencingFeature(self, feature=QgsFeature()):
        self.deactivateMapTool()
        self.referencingFeature = QgsFeature(feature)
        self.deleteWrapper()

        # disable relation reference widget if no referencing feature
        self.referencedFeatureLayout.setEnabled(feature.isValid())

        # set line edit
        if not self.relation.isValid() or not feature.isValid():
            self.referencingFeatureLineEdit.clear()
            return
        self.referencingFeatureLineEdit.setText("%s" % feature.id())

        fieldIdx = self.referencingFieldIndex()
        widgetConfig = self.relation.referencingLayer().editorWidgetV2Config(
            fieldIdx)
        self.relationWidgetWrapper = QgsEditorWidgetRegistry.instance().create(
            "RelationReference", self.relation.referencingLayer(), fieldIdx,
            widgetConfig, self.relationReferenceWidget, self,
            self.editorContext)

        self.relationWidgetWrapper.setEnabled(
            self.relation.referencingLayer().isEditable())
        self.relationWidgetWrapper.setValue(feature[fieldIdx])
        self.relationWidgetWrapper.valueChanged.connect(self.foreignKeyChanged)
        # override field definition to allow map identification
        self.relationReferenceWidget.setAllowMapIdentification(True)
        self.relationReferenceWidget.setEmbedForm(False)

        # update drawn link
        self.highlightReferencingFeature()
        self.drawLink()

    def deleteWrapper(self):
        if self.relationWidgetWrapper is not None:
            self.relationWidgetWrapper.valueChanged.disconnect(
                self.foreignKeyChanged)
            self.relationWidgetWrapper.setValue(None)
            del self.relationWidgetWrapper
            self.relationWidgetWrapper = None

    def foreignKeyChanged(self, newKey):
        if not self.relation.isValid() or not self.relation.referencingLayer(
        ).isEditable() or not self.referencingFeature.isValid():
            self.drawLink()
            return
        if not self.relation.referencingLayer().editBuffer(
        ).changeAttributeValue(self.referencingFeature.id(),
                               self.referencingFieldIndex(), newKey):
            self.iface.messageBar().pushMessage(
                "Link It", "Cannot change attribute value.",
                QgsMessageBar.CRITICAL)
        self.drawLink()

    def relationEditableChanged(self):
        if self.relationWidgetWrapper is not None:
            self.relationWidgetWrapper.setEnabled(
                self.relation.isValid()
                and self.relation.referencingLayer().isEditable())

    def layerValueChangedOutside(self, fid, fieldIdx, value):
        if not self.relation.isValid() or not self.referencingFeature.isValid(
        ) or self.relationWidgetWrapper is None:
            return
        # not the correct feature
        if fid != self.referencingFeature.id():
            return
        # not the correct field
        if fieldIdx != self.referencingFieldIndex():
            return
        # widget already has this value
        if value == self.relationWidgetWrapper.value():
            return
        self.relationWidgetWrapper.valueChanged.disconnect(
            self.foreignKeyChanged)
        self.relationWidgetWrapper.setValue(value)
        self.relationWidgetWrapper.valueChanged.connect(self.foreignKeyChanged)

    def referencingFieldIndex(self):
        if not self.relation.isValid():
            return -1
        fieldName = self.relation.fieldPairs().keys()[0]
        fieldIdx = self.relation.referencingLayer().fieldNameIndex(fieldName)
        return fieldIdx

    @pyqtSlot(bool, name="on_drawButton_toggled")
    def drawLink(self):
        self.settings.setValue("drawEnabled", self.drawButton.isChecked())
        self.linkRubber.reset()
        if not self.drawButton.isChecked(
        ) or not self.referencingFeature.isValid(
        ) or not self.relation.isValid():
            return

        referencedFeature = self.relationReferenceWidget.referencedFeature()
        if not referencedFeature.isValid():
            return

        p1 = self.centroid(self.relation.referencedLayer(), referencedFeature)
        p2 = self.centroid(self.relation.referencingLayer(),
                           self.referencingFeature)
        geom = arc(p1, p2)

        self.linkRubber.setToGeometry(geom, None)
        self.linkRubber.setWidth(self.settings.value("rubberWidth"))
        self.linkRubber.setColor(self.settings.value("rubberColor"))
        self.linkRubber.setLineStyle(Qt.DashLine)

    def centroid(self, layer, feature):
        geom = feature.geometry()
        if geom.type() == QGis.Line:
            geom = geom.interpolate(geom.length() / 2)
        else:
            geom = geom.centroid()
        return self.iface.mapCanvas().mapSettings().layerToMapCoordinates(
            layer, geom.asPoint())

    @pyqtSlot(name="on_highlightReferencingFeatureButton_clicked")
    def highlightReferencingFeature(self):
        self.deleteHighlight()
        if not self.relation.isValid() or not self.referencingFeature.isValid(
        ):
            return

        self.featureHighlight = QgsHighlight(
            self.iface.mapCanvas(), self.referencingFeature.geometry(),
            self.relation.referencingLayer())
        settings = QSettings()
        color = QColor(
            settings.value("/Map/highlight/color",
                           QGis.DEFAULT_HIGHLIGHT_COLOR.name()))
        alpha = int(
            settings.value("/Map/highlight/colorAlpha",
                           QGis.DEFAULT_HIGHLIGHT_COLOR.alpha()))
        bbuffer = float(
            settings.value("/Map/highlight/buffer",
                           QGis.DEFAULT_HIGHLIGHT_BUFFER_MM))
        minWidth = float(
            settings.value("/Map/highlight/minWidth",
                           QGis.DEFAULT_HIGHLIGHT_MIN_WIDTH_MM))

        self.featureHighlight.setColor(color)
        color.setAlpha(alpha)
        self.featureHighlight.setFillColor(color)
        self.featureHighlight.setBuffer(bbuffer)
        self.featureHighlight.setMinWidth(minWidth)
        self.featureHighlight.show()

        timer = QTimer(self)
        timer.setSingleShot(True)
        timer.timeout.connect(self.deleteHighlight)
        timer.start(3000)

    def deleteHighlight(self):
        if self.featureHighlight:
            del self.featureHighlight
        self.featureHighlight = None
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")