Exemplo n.º 1
0
    def onIdentified(self, selected_layer, selected_feature):
        selected_type = ""
        if self.application_settings.get_layers_route_node_name(
        ) == selected_layer.sourceName():
            selected_type = self.application_settings.get_types_route_node()
        elif self.application_settings.get_layers_route_segment_name(
        ) == selected_layer.sourceName():
            selected_type = self.application_settings.get_types_route_segment()
        else:
            self.identifyHighlight.hide()
            return

        if self.identifyHighlight is not None:
            self.identifyHighlight.hide()

        color = QColor(0, 255, 0)
        self.identifyHighlight = QgsHighlight(self.iface.mapCanvas(),
                                              selected_feature.geometry(),
                                              selected_layer)
        self.identifyHighlight.setWidth(3)
        self.identifyHighlight.setColor(color)
        self.identifyHighlight.show()

        mrid = selected_feature.attribute("mrid")

        self.last_identified_feature_mrid = mrid
        self.last_identified_feature_type = selected_type

        if selected_type != "":
            self.identifyNetworkElementHandler.handle(mrid, selected_type)
Exemplo n.º 2
0
    def runTestForLayer(self, layer, testname):
        tempdir = tempfile.mkdtemp()

        layer = QgsVectorLayer(layer, 'Layer', 'ogr')
        QgsProject.instance().addMapLayer(layer)
        self.iface.mapCanvas().setExtent(layer.extent())

        geom = next(layer.getFeatures()).geometry()

        highlight = QgsHighlight(self.iface.mapCanvas(), geom, layer)
        color = QColor(Qt.red)
        highlight.setColor(color)
        highlight.setWidth(2)
        color.setAlpha(50)
        highlight.setFillColor(color)
        highlight.show()

        image = QImage(QSize(400, 400), QImage.Format_ARGB32)
        image.fill(Qt.white)
        painter = QPainter()
        painter.begin(image)
        self.iface.mapCanvas().render(painter)
        painter.end()
        control_image = os.path.join(tempdir, 'highlight_{}.png'.format(testname))
        image.save(control_image)
        checker = QgsRenderChecker()
        checker.setControlPathPrefix("highlight")
        checker.setControlName("expected_highlight_{}".format(testname))
        checker.setRenderedImage(control_image)
        self.assertTrue(checker.compareImages("highlight_{}".format(testname)))
        shutil.rmtree(tempdir)
Exemplo n.º 3
0
    def highlight_spatial_unit(
            self, spatial_unit, geom, map_canvas
    ):
        layer = self._iface.activeLayer()
        map_canvas.setExtent(layer.extent())
        map_canvas.refresh()

        if self.spatial_unit_layer(spatial_unit, layer):

            self.clear_sel_highlight()

            qgis_geom = qgsgeometry_from_wkbelement(geom)

            self.sel_highlight = QgsHighlight(
                map_canvas, qgis_geom, layer
            )
            rgba = selection_color()
            self.sel_highlight.setFillColor(rgba)

            self.sel_highlight.setWidth(3)
            self.sel_highlight.show()

            extent = qgis_geom.boundingBox()
            extent.scale(1.5)
            map_canvas.setExtent(extent)
            map_canvas.refresh()
        else:
            return
Exemplo n.º 4
0
    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)
Exemplo n.º 5
0
    def highlight_feature(self, canvas_extent=CanvasExtent.Fixed):
        if self.canvas is None or not self.feature.isValid():
            return

        geom = self.feature.geometry()

        if geom is None:
            return

        if canvas_extent == CanvasExtent.Scale:
            feature_bounding_box = geom.boundingBox()
            feature_bounding_box = self.canvas.mapSettings(
            ).layerToMapCoordinates(self.layer, feature_bounding_box)
            extent = self.canvas.extent()
            if not extent.contains(feature_bounding_box):
                extent.combineExtentWith(feature_bounding_box)
                extent.scale(1.1)
                self.canvas.setExtent(extent)
                self.canvas.refresh()

        elif canvas_extent == 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)
Exemplo n.º 6
0
    def runTestForLayer(self, layer, testname):
        tempdir = tempfile.mkdtemp()

        layer = QgsVectorLayer(layer, 'Layer', 'ogr')
        QgsProject.instance().addMapLayer(layer)
        self.iface.mapCanvas().setExtent(layer.extent())

        geom = next(layer.getFeatures()).geometry()

        highlight = QgsHighlight(self.iface.mapCanvas(), geom, layer)
        color = QColor(Qt.red)
        highlight.setColor(color)
        highlight.setWidth(2)
        color.setAlpha(50)
        highlight.setFillColor(color)
        highlight.show()

        image = QImage(QSize(400, 400), QImage.Format_ARGB32)
        image.fill(Qt.white)
        painter = QPainter()
        painter.begin(image)
        self.iface.mapCanvas().render(painter)
        painter.end()
        control_image = os.path.join(tempdir, 'highlight_{}.png'.format(testname))
        image.save(control_image)
        checker = QgsRenderChecker()
        checker.setControlPathPrefix("highlight")
        checker.setControlName("expected_highlight_{}".format(testname))
        checker.setRenderedImage(control_image)
        self.assertTrue(checker.compareImages("highlight_{}".format(testname)))
        shutil.rmtree(tempdir)
Exemplo n.º 7
0
 def on_chooseId_currentIndexChanged(self, thisIndex):
     self.clearHighlight()
     aPkValue = self.chooseId.currentText()
     aGeom = self.featDict[self.pkValues[aPkValue]].geometry()
     hlColor, hlFillColor, hlBuffer, hlMinWidth = dtGetHighlightSettings()
     self.hl = QgsHighlight(self.iface.mapCanvas(), aGeom, self.editLayer)
     self.hl.setColor(hlColor)
     self.hl.setFillColor(hlFillColor)
     self.hl.setBuffer(hlBuffer)
     self.hl.setWidth(hlMinWidth)
     self.hl.show()
Exemplo n.º 8
0
    def highlight(self, error, crs):
        self.clearHighlight()
        if not error: return

        # QgsHighlight does reprojection from layer CRS
        layer = QgsVectorLayer('Point?crs=' + crsString(crs), 'LRS error highlight', 'memory')
        self.errorHighlight = QgsHighlight(self.mapCanvas, error.geo, layer)
        # highlight point size is hardcoded in QgsHighlight
        self.errorHighlight.setWidth(2)
        self.errorHighlight.setColor(Qt.yellow)
        self.errorHighlight.show()
Exemplo n.º 9
0
    def multi_select_highlight(self, index):
        """
        Highlights a feature with rubberBald class when selecting
        features are more than one.
        :param index: Selected QTreeView item index
        :type Integer
        :return: None
        """
        map = self.iface.mapCanvas()
        try:

            # Get the selected item text using the index
            selected_item = self.model.itemFromIndex(index)
            # Use mutli-select only when more than 1 items are selected.
            if self.layer.selectedFeatures() < 2:
                return
            self.selected_root = selected_item
            # Split the text to get the key and value.
            selected_item_text = selected_item.text()

            selected_value = selected_item.data()
            # If the first word is feature, expand & highlight.
            if selected_item_text == format_name(self.spatial_unit.short_name):
                self.view.expand(index)  # expand the item
                # Clear any existing highlight
                self.clear_sel_highlight()
                # Insert highlight
                # Create expression to target the selected feature
                expression = QgsExpression(
                    "\"id\"='" + str(selected_value) + "'"
                )
                # Get feature iteration based on the expression
                ft_iteration = self.layer.getFeatures(
                    QgsFeatureRequest(expression)
                )

                # Retrieve geometry and attributes
                for feature in ft_iteration:
                    # Fetch geometry
                    geom = feature.geometry()
                    self.sel_highlight = QgsHighlight(map, geom, self.layer)

                    self.sel_highlight.setFillColor(selection_color())
                    self.sel_highlight.setWidth(4)
                    self.sel_highlight.setColor(QColor(212,95,0, 255))
                    self.sel_highlight.show()
                    break
        except AttributeError:
            # pass attribute error on child items such as party
            pass
        except IndexError:
            pass
Exemplo n.º 10
0
class DigitizingToolsChooseRemaining(QtWidgets.QDialog, FORM_CLASS):
    def __init__(self, iface, editLayer, pkValues, featDict, title):
        QtWidgets.QDialog.__init__(self)
        self.setupUi(self)
        self.iface = iface
        self.editLayer = editLayer
        self.pkValues = pkValues
        self.featDict = featDict
        self.chooseId.addItems(list(self.pkValues.keys()))
        self.setWindowTitle(title)
        self.label.setText(QtWidgets.QApplication.translate(
            "digitizingtools", "Choose which already existing feature should remain"))
        self.buttonBox.rejected.connect(self.reject)
        self.buttonBox.accepted.connect(self.accept)

    @QtCore.pyqtSlot(int)
    def on_chooseId_currentIndexChanged(self, thisIndex):
        aPkValue = self.chooseId.currentText()
        aGeom = self.featDict[self.pkValues[aPkValue]].geometry()
        hlColor, hlFillColor, hlBuffer,  hlMinWidth = dtGetHighlightSettings()
        self.hl = QgsHighlight(self.iface.mapCanvas(), aGeom, self.editLayer)
        self.hl.setColor(hlColor)
        self.hl.setFillColor(hlFillColor)
        self.hl.setBuffer(hlBuffer)
        self.hl.setWidth(hlMinWidth)

    @QtCore.pyqtSlot()
    def reject(self):
        self.done(0)

    @QtCore.pyqtSlot()
    def accept(self):
        self.pkValueToKeep = self.chooseId.currentText()
        self.done(1)
 def _addHighlight(self, canvas, geometry, layer):
     hl = QgsHighlight(canvas, geometry, layer)
     color = QColor(QSettings().value('/Map/highlight/color', QGis.DEFAULT_HIGHLIGHT_COLOR.name(), str))
     alpha = QSettings().value('/Map/highlight/colorAlpha', QGis.DEFAULT_HIGHLIGHT_COLOR.alpha(), int)
     buff = QSettings().value('/Map/highlight/buffer', QGis.DEFAULT_HIGHLIGHT_BUFFER_MM, float)
     minWidth = QSettings().value('/Map/highlight/minWidth', QGis.DEFAULT_HIGHLIGHT_MIN_WIDTH_MM, float)
     hl.setColor(color)
     color.setAlpha(alpha)
     hl.setFillColor(color)
     hl.setBuffer(buff)
     hl.setMinWidth(minWidth)
     self._highlights.append(hl)
Exemplo n.º 12
0
    def highlight_spatial_unit(
            self, spatial_unit, geom, map_canvas
    ):
        layer = self._iface.activeLayer()
        map_canvas.setExtent(layer.extent())
        map_canvas.refresh()

        if self.spatial_unit_layer(spatial_unit, layer):

            self.clear_sel_highlight()

            qgis_geom = qgsgeometry_from_wkbelement(geom)

            self.sel_highlight = QgsHighlight(
                map_canvas, qgis_geom, layer
            )
            rgba = selection_color()
            self.sel_highlight.setFillColor(rgba)

            self.sel_highlight.setWidth(3)
            self.sel_highlight.show()

            extent = qgis_geom.boundingBox()
            extent.scale(1.5)
            map_canvas.setExtent(extent)
            map_canvas.refresh()
        else:
            return
Exemplo n.º 13
0
    def setHighlight(self, ly, vertex):
        if self.highlight:
            self.highlight.hide()
            self.highlight = None
        if vertex:
            color = QColor(255, 0, 100, 255)
            lv = vertex + [vertex[0]]
            g = QgsGeometry.fromPolyline(lv).convertToType(2)

            print(g.asWkt(3))
            self.highlight = QgsHighlight(self.iface.mapCanvas(), g, ly)
            self.highlight.setColor(color)
            self.highlight.setWidth(5)
            color.setAlpha(50)
            self.highlight.setFillColor(color)
            self.highlight.show()
Exemplo n.º 14
0
class DigitizingToolsChooseRemaining(QtWidgets.QDialog, FORM_CLASS):
    def __init__(self, iface, editLayer, pkValues, featDict, title):
        QtWidgets.QDialog.__init__(self)
        self.setupUi(self)
        self.iface = iface
        self.editLayer = editLayer
        self.pkValues = pkValues
        self.featDict = featDict
        self.chooseId.addItems(list(self.pkValues.keys()))
        self.setWindowTitle(title)
        self.label.setText(
            QtWidgets.QApplication.translate(
                "digitizingtools",
                "Choose which already existing feature should remain"))
        self.buttonBox.rejected.connect(self.reject)
        self.buttonBox.accepted.connect(self.accept)

    def clearHighlight(self):
        try:
            self.hl.hide()
        except:
            pass

    @QtCore.pyqtSlot(int)
    def on_chooseId_currentIndexChanged(self, thisIndex):
        self.clearHighlight()
        aPkValue = self.chooseId.currentText()
        aGeom = self.featDict[self.pkValues[aPkValue]].geometry()
        hlColor, hlFillColor, hlBuffer, hlMinWidth = dtGetHighlightSettings()
        self.hl = QgsHighlight(self.iface.mapCanvas(), aGeom, self.editLayer)
        self.hl.setColor(hlColor)
        self.hl.setFillColor(hlFillColor)
        self.hl.setBuffer(hlBuffer)
        self.hl.setWidth(hlMinWidth)
        self.hl.show()

    @QtCore.pyqtSlot()
    def reject(self):
        self.clearHighlight()
        self.done(0)

    @QtCore.pyqtSlot()
    def accept(self):
        self.clearHighlight()
        self.pkValueToKeep = self.chooseId.currentText()
        self.done(1)
    def highlight_courant(self):
        """highlight animated flowline layer where Courant number is higher than a given value (use velocity variable as flowline-results)"""

        if len(QgsProject.instance().mapLayersByName("line_results")) == 0:
            self.iface.messageBar().pushMessage(
                "Warning",
                'Couldn\'t find line_results layer, click "Animation on" button',
                level=Qgis.Warning,
            )
            return

        # layer found
        canvas = self.iface.mapCanvas()

        line_results = QgsProject.instance().mapLayersByName("line_results")[0]
        global_settings_layer = QgsProject.instance().mapLayersByName(
            "v2_global_settings"
        )[0]
        timestep = list(global_settings_layer.getFeatures())[0][
            "sim_time_step"
        ]  # [0] -> [self.selected_scenario_index]
        d = QgsDistanceArea()
        d.setEllipsoid("WGS84")

        features = line_results.getFeatures()
        for feature in features:
            kcu = feature["kcu"]
            if kcu in [0, 1, 2, 3, 5, 100, 101]:
                geometry = feature.geometry()
                length = d.measureLength(geometry)

                velocity = abs(feature["result"])

                courant = velocity * timestep / length

                if courant > self.courantThreshold.value():
                    color = QtGui.QColor(Qt.red)
                    highlight = QgsHighlight(canvas, feature, line_results)
                    highlight.setColor(color)
                    highlight.setMinWidth(courant / 2)
                    # highlight.setBuffer()
                    color.setAlpha(50)
                    highlight.setFillColor(color)
                    highlight.show()
                    self.highlights.append(highlight)
Exemplo n.º 16
0
 def on_chooseId_currentIndexChanged(self, thisIndex):
     aPkValue = self.chooseId.currentText()
     aGeom = self.featDict[self.pkValues[aPkValue]].geometry()
     hlColor, hlFillColor, hlBuffer,  hlMinWidth = dtGetHighlightSettings()
     self.hl = QgsHighlight(self.iface.mapCanvas(), aGeom, self.editLayer)
     self.hl.setColor(hlColor)
     self.hl.setFillColor(hlFillColor)
     self.hl.setBuffer(hlBuffer)
     self.hl.setWidth(hlMinWidth)
Exemplo n.º 17
0
 def _addHighlight(self, canvas, geometry, layer):
     hl = QgsHighlight(canvas, geometry, layer)
     color = QColor(QSettings().value('/Map/highlight/color',
                                      QGis.DEFAULT_HIGHLIGHT_COLOR.name(),
                                      str))
     alpha = QSettings().value('/Map/highlight/colorAlpha',
                               QGis.DEFAULT_HIGHLIGHT_COLOR.alpha(), int)
     buff = QSettings().value('/Map/highlight/buffer',
                              QGis.DEFAULT_HIGHLIGHT_BUFFER_MM, float)
     minWidth = QSettings().value('/Map/highlight/minWidth',
                                  QGis.DEFAULT_HIGHLIGHT_MIN_WIDTH_MM,
                                  float)
     hl.setColor(color)
     color.setAlpha(alpha)
     hl.setFillColor(color)
     hl.setBuffer(buff)
     hl.setMinWidth(minWidth)
     self._highlights.append(hl)
Exemplo n.º 18
0
 def markFeature(self, lay, feat):
     try:
         color = QColor(Qt.red)
         highlight = QgsHighlight(self.iface.mapCanvas(), feat, lay)
         highlight.setColor(color)
         color.setAlpha(50)
         highlight.setFillColor(color)
         highlight.show()
         return highlight
     except Exception as e:
         self.info.err(e)
Exemplo n.º 19
0
    def pointPicked(self, event):
        for b in self.rubberBands:
            del b
        self.rubberBands[:] = []

        fieldX = self.cmbXField.currentField()
        fieldY = self.cmbYField.currentField()

        artist = event.artist
        indices = event.ind
        for i in indices:
            x = self.xData[artist.name][i]
            y = self.yData[artist.name][i]

            if isinstance(x, int):
                expr = '"{}" = {} AND '.format(fieldX, x)
            elif isinstance(x, float):
                expr = 'abs("{}" - {}) <= 0.0000001 AND '.format(fieldX, x)
            elif isinstance(x, (str, unicode)):
                expr = """"{}" = '{}' AND """.format(fieldX, x)
            else:
                expr = """"{}" = '{}' AND """.format(fieldX, x.toString('yyyy-MM-dd'))

            if isinstance(y, float):
                expr += 'abs("{}" - {}) <= 0.0000001'.format(fieldY, y)
            elif isinstance(y, (str, unicode)):
                expr += """"{}" = '{}'""".format(fieldY, y)
            else:
                expr += '"{}" = {}'.format(fieldY, y)

            layer = self.cmbLayer.currentLayer()
            expression = QgsExpression(expr)
            context = QgsExpressionContext()
            context.appendScope(QgsExpressionContextUtils.globalScope())
            context.appendScope(QgsExpressionContextUtils.projectScope())
            context.appendScope(QgsExpressionContextUtils.mapSettingsScope(self.canvas.mapSettings()))
            context.appendScope(QgsExpressionContextUtils.layerScope(layer))

            request = QgsFeatureRequest(expression, context)
            for f in layer.getFeatures(request):
                hl = QgsHighlight(self.canvas, f.geometry(), layer)
                hl.setColor(QColor(255, 0, 0))
                hl.setWidth(2)
                self.rubberBands.append(hl)
Exemplo n.º 20
0
    def setCurrentStation(self, feature):
        """ set the panel's current prediction station to the one described by the given feature
        """
        self.stationFeature = feature
        self.stationZone = stationTimeZone(feature)
        self.stationLabel.setText(feature['name'])

        self.updateTime()
        self.updateStationLink()
        self.loadStationPredictions()

        if self.stationHighlight is not None:
            self.stationHighlight.hide()

        self.stationHighlight = QgsHighlight(self.canvas, self.stationFeature,
                                             self.currentStationsLayer)
        self.stationHighlight.setColor(QColor(Qt.red))
        self.stationHighlight.setFillColor(QColor(Qt.red))
        self.stationHighlight.show()
Exemplo n.º 21
0
    def highlightLocatePoint(self):
        # #debug ('highlightLocatePoint')
        self.clearLocateHighlight()
        if not self.locatePoint: return
        if not self.locateHighlightCheckBox.isChecked(): return

        mapCanvas = self.iface.mapCanvas()
        mapSettings = mapCanvas.mapSettings()
        # QgsHighlight does reprojection from layer CRS
        crs = getProjectCrs() if isProjectCrsEnabled() else self.lrsLayer.crs
        layer = QgsVectorLayer('Point?crs=' + crsString(crs),
                               'LRS locate highlight', 'memory')
        #self.locateHighlight = QgsHighlight(mapCanvas, QgsGeometry.fromPoint(self.locatePoint), layer)
        # QgsGeometry(QgsPoint) takes ownership!
        self.locateHighlight = QgsHighlight(
            mapCanvas, QgsGeometry(QgsPoint(self.locatePoint)), layer)
        # highlight point size is hardcoded in QgsHighlight
        self.locateHighlight.setWidth(2)
        self.locateHighlight.setColor(Qt.yellow)
        self.locateHighlight.show()
Exemplo n.º 22
0
 def highlight_features(self):
     for item in self.highlight:
         self.canvas.scene().removeItem(item)
     del self.highlight[:]
     del self.highlight_rows[:]
     index = self.tabWidget.currentIndex()
     tab = self.tabWidget.widget(index)
     if self.tabWidget.count() != 0:
         table = self.tabWidget.widget(index).findChildren(QTableWidget)[0]
         nb = 0
         area = 0
         length = 0
         items = table.selectedItems()
         for item in items:
             if item.row() not in self.highlight_rows:
                 if self.selectGeom:
                     highlight = QgsHighlight(self.canvas, item.feature.geometry(), self.tabWidget.widget(index).layer)
                 else:
                     highlight = QgsHighlight(self.canvas, item.feature.geometry().centroid(), self.tabWidget.widget(index).layer)
                 highlight.setColor(QColor(255,0,0))
                 self.highlight.append(highlight)
                 self.highlight_rows.append(item.row())
                 g = QgsGeometry(item.feature.geometry())
                 g.transform(QgsCoordinateTransform(tab.layer.crs(), QgsCoordinateReferenceSystem(2154), QgsProject.instance())) # geometry reprojection to get meters
                 nb += 1
                 area += g.area()
                 length += g.length()
         if tab.layer.geometryType()==QgsWkbTypes.PolygonGeometry:
             tab.sb.showMessage(self.tr('Selected features')+': '+str(nb)+'  '+self.tr('Area')+': '+"%.2f"%area+' m'+u'²')
         elif tab.layer.geometryType()==QgsWkbTypes.LineGeometry:
             tab.sb.showMessage(self.tr('Selected features')+': '+str(nb)+'  '+self.tr('Length')+': '+"%.2f"%length+' m')
         else:
             tab.sb.showMessage(self.tr('Selected features')+': '+str(nb))
    def onResultTableSelChanged(self):
        cur_row_index = self.dockWidget.tableResult.currentRow()
        if cur_row_index > -1:
            self.clearHighlight(self.intersected_h_list)

            f_geometry = QgsGeometry()
            f_geometry = QgsGeometry.fromWkt(
                self.dockWidget.tableResult.item(cur_row_index, 1).text())
            h = QgsHighlight(self.iface.mapCanvas(), f_geometry,
                             self.current_layer)
            h.setColor(QColor(0, 15, 183, 220))
            h.setWidth(6)
            h.setFillColor(QColor(0, 15, 183, 150))
            self.intersected_h_list.append(h)
Exemplo n.º 24
0
    def testBugfix48471(self):
        """ Test scenario of https://github.com/qgis/QGIS/issues/48471 """

        lines_shp = os.path.join(TEST_DATA_DIR, 'lines.shp')
        layer = QgsVectorLayer(lines_shp, 'Layer', 'ogr')
        QgsProject.instance().addMapLayer(layer)
        self.iface.mapCanvas().setExtent(layer.extent())

        geom = next(layer.getFeatures()).geometry()

        highlight = QgsHighlight(self.iface.mapCanvas(), geom, layer)
        highlight.setBuffer(12345)

        try:
            found = False
            for item in self.iface.mapCanvas().scene().items():
                if isinstance(item, QgsHighlight):
                    if item.buffer() == 12345:
                        found = True
            self.assertTrue(found)
        finally:
            self.iface.mapCanvas().scene().removeItem(highlight)
Exemplo n.º 25
0
    def test_feature_transformation(self):
        poly_shp = os.path.join(TEST_DATA_DIR, 'polys.shp')
        layer = QgsVectorLayer(poly_shp, 'Layer', 'ogr')

        sub_symbol = QgsFillSymbol.createSimple({
            'color': '#8888ff',
            'outline_style': 'no'
        })

        sym = QgsFillSymbol()
        buffer_layer = QgsGeometryGeneratorSymbolLayer.create(
            {'geometryModifier': 'buffer($geometry, -0.4)'})
        buffer_layer.setSymbolType(QgsSymbol.Fill)
        buffer_layer.setSubSymbol(sub_symbol)
        sym.changeSymbolLayer(0, buffer_layer)
        layer.setRenderer(QgsSingleSymbolRenderer(sym))

        canvas = QgsMapCanvas()
        canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857'))
        canvas.setFrameStyle(0)
        canvas.resize(600, 400)
        self.assertEqual(canvas.width(), 600)
        self.assertEqual(canvas.height(), 400)

        canvas.setLayers([layer])
        canvas.setExtent(QgsRectangle(-11960254, 4247568, -11072454, 4983088))
        canvas.show()

        # need to wait until first redraw can occur (note that we first need to wait till drawing starts!)
        while not canvas.isDrawing():
            app.processEvents()
        canvas.waitWhileRendering()

        feature = layer.getFeature(1)
        self.assertTrue(feature.isValid())

        highlight = QgsHighlight(canvas, feature, layer)
        color = QColor(Qt.red)
        highlight.setColor(color)
        color.setAlpha(50)
        highlight.setFillColor(color)
        highlight.show()
        highlight.show()

        self.assertTrue(
            self.canvasImageCheck('highlight_transform', 'highlight_transform',
                                  canvas))
Exemplo n.º 26
0
    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)
Exemplo n.º 27
0
    def onMapClickedTableSelChanged(self):
        cur_row_index = self.map_clicked_dlg.tableClickedWays.currentRow()
        if cur_row_index > -1:
            self.clearAllHighlights()

            f_geometry = QgsGeometry()
            f_geometry = QgsGeometry.fromWkt(
                self.map_clicked_dlg.tableClickedWays.item(cur_row_index,
                                                           1).text())

            h = QgsHighlight(self.iface.mapCanvas(), f_geometry,
                             self.current_layer)
            h.setColor(QColor(0, 15, 183, 220))
            h.setWidth(6)
            h.setFillColor(QColor(0, 15, 183, 150))
            self.mapclicked_h_list.append(h)

        self.setButtonOkStatus()
Exemplo n.º 28
0
    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)
Exemplo n.º 29
0
class LrsErrorVisualizer(object):
    def __init__(self, mapCanvas):
        self.errorHighlight = None
        self.mapCanvas = mapCanvas

    def __del__(self):
        if self.errorHighlight:
            del self.errorHighlight

    def clearHighlight(self):
        if self.errorHighlight:
            del self.errorHighlight
            self.errorHighlight = None

    def highlight(self, error, crs):
        self.clearHighlight()
        if not error: return

        # QgsHighlight does reprojection from layer CRS
        layer = QgsVectorLayer('Point?crs=' + crsString(crs), 'LRS error highlight', 'memory')
        self.errorHighlight = QgsHighlight(self.mapCanvas, error.geo, layer)
        # highlight point size is hardcoded in QgsHighlight
        self.errorHighlight.setWidth(2)
        self.errorHighlight.setColor(Qt.yellow)
        self.errorHighlight.show()

    def zoom(self, error, crs):
        if not error: return
        geo = error.geo
        mapSettings = self.mapCanvas.mapSettings()
        if isProjectCrsEnabled() and getProjectCrs() != crs:
            geo = QgsGeometry(error.geo)
            transform = QgsCoordinateTransform(crs, QgsProject().instance().crs())
            geo.transform(transform)

        if geo.type() == QgsWkbTypes.PointGeometry:
            p = geo.asPoint()
            bufferCrs = getProjectCrs() if isProjectCrsEnabled() else crs
            b = 2000 if not bufferCrs.isGeographic() else 2000 / 100000  # buffer
            extent = QgsRectangle(p.x() - b, p.y() - b, p.x() + b, p.y() + b)
        else:  # line
            extent = geo.boundingBox()
            extent.scale(2)
        self.mapCanvas.setExtent(extent)
        self.mapCanvas.refresh();
    def handle(self, message):
        if message.username != self.settings.get_user_name_prefix():
            return

        for highlight in self.highlightFeatures:
            self.iface.mapCanvas().scene().removeItem(highlight)

        self.highlightFeatures = []

        if len(message.identifiedFeatureMrids) == 0:
            return

        layer = None
        if message.featureType == self.settings.get_types_route_segment():
            layer = QgsProject.instance().mapLayersByName(
                self.settings.get_layers_route_segment_name())[0]
        elif message.featureType == self.settings.get_types_route_node():
            layer = QgsProject.instance().mapLayersByName(
                self.settings.get_layers_route_node_name())[0]

        filterExpression = ""
        for i in range(len(message.identifiedFeatureMrids)):
            mrid = message.identifiedFeatureMrids[i]
            if i == len(message.identifiedFeatureMrids) - 1:
                filterExpression += f'"mrid" = \'{mrid}\''
            else:
                filterExpression += f'"mrid" = \'{mrid}\' OR '

        features = layer.getFeatures(
            QgsFeatureRequest().setFilterExpression(filterExpression))

        color = QColor(64, 224, 208)
        for feature in features:
            identifyHighlight = QgsHighlight(self.iface.mapCanvas(),
                                             feature.geometry(), layer)
            identifyHighlight.setWidth(5)
            identifyHighlight.setColor(color)
            self.highlightFeatures.append(identifyHighlight)

        for highlight in self.highlightFeatures:
            highlight.show()

        layer.triggerRepaint()
Exemplo n.º 31
0
 def highlightByGeometry(self, geometry, color=QColor(255, 0, 0, 128)):
     highlight = QgsHighlight(self.mTheCanvas, geometry, self.mTheLayer)
     highlight.setColor(color)
     highlight.setFillColor(color)
     highlight.setBuffer(0.5)
     highlight.setMinWidth(6)
     highlight.setWidth(6)
     highlight.show()
     self.highlightList.append(highlight)
     return
Exemplo n.º 32
0
 def highlightFeature(self, theFeature):
     highlight = QgsHighlight(self.mTheCanvas, theFeature.geometry(),
                              self.mTheLayer)
     highlight.setColor(QColor(255, 0, 0, 128))
     highlight.setFillColor(QColor(255, 0, 0, 128))
     highlight.setBuffer(0.5)
     highlight.setMinWidth(6)
     highlight.setWidth(6)
     highlight.show()
     self.highlightList.append(highlight)
     return
Exemplo n.º 33
0
class TinTools:
    def __init__(self, iface):
        self.iface = iface
        self.toolbar = None
        self.highlight = None
        self.msgBar = iface.messageBar()
        self.plugin_dir = os.path.dirname(__file__)
        print('plugin init en ' + self.plugin_dir)

    def initGui(self):
        self.toolbar = self.iface.addToolBar(u'TIN Tools')
        self.toolbar.setObjectName(u'tintools')
        label = QLabel('Capa TIN:')
        self.toolbar.addWidget(label)
        self.tin_cb = QgsMapLayerComboBox()
        self.tin_cb.setMinimumWidth(200)
        self.tin_cb.setFilters(QgsMapLayerProxyModel.VectorLayer)
        self.tin_cb.layerChanged.connect(self.tinLayerChanged)
        self.toolbar.addWidget(self.tin_cb)

        #        icon_path = self.plugin_dir +'/icon.png'
        #        icon = QIcon(icon_path)
        #'\u0394 \u2B16  \u20E4  \u2350 \u21C8 \u2963 \u2B7F \u2b85 \u23C4  \u25e9'
        self.calc_plane_action = QAction('\u0394', self.iface.mainWindow())
        self.calc_plane_action.triggered.connect(self.calcPlaneEquation)
        self.toolbar.addAction(self.calc_plane_action)

        self.calc_z = QAction('\u21C8', self.iface.mainWindow())
        self.calc_z.triggered.connect(self.calcZ)
        self.toolbar.addAction(self.calc_z)

        self.adjust_to_tin = QAction('\u25e9', self.iface.mainWindow())
        self.adjust_to_tin.triggered.connect(self.adjustToTin)
        self.toolbar.addAction(self.adjust_to_tin)

        self.tinLayerChanged(self.tin_cb.currentLayer())

    def unload(self):
        self.planeCalc = None
        self.setHighlight(None, None)
        self.iface.removeToolBarIcon(self.calc_plane_action)
        self.iface.removeToolBarIcon(self.calc_z)
        self.iface.removeToolBarIcon(self.adjust_to_tin)
        del self.toolbar
        print('unload toolbar5')

    def msg(self, text):
        self.msgBar.pushWarning('TIN tool', text)

    def info(self, text):
        self.msgBar.pushInfo('TIN tool', text)

    def setHighlight(self, ly, vertex):
        if self.highlight:
            self.highlight.hide()
            self.highlight = None
        if vertex:
            color = QColor(255, 0, 100, 255)
            lv = vertex + [vertex[0]]
            g = QgsGeometry.fromPolyline(lv).convertToType(2)

            print(g.asWkt(3))
            self.highlight = QgsHighlight(self.iface.mapCanvas(), g, ly)
            self.highlight.setColor(color)
            self.highlight.setWidth(5)
            color.setAlpha(50)
            self.highlight.setFillColor(color)
            self.highlight.show()

    def tinLayerChanged(self, layer):
        self.calc_plane_action.setEnabled(layer is not None)
        self.adjust_to_tin.setEnabled(layer is not None)
        self.calc_z.setEnabled(False)
        self.planeCalc = None
        self.setHighlight(None, None)

    def calcPlaneEquation(self):
        ly = self.tin_cb.currentLayer()
        self.setHighlight(None, None)
        if not ly:
            self.msg('No hay ninguna capa seleccionada')
            return
        ver = None
        feat = ly.selectedFeatures()
        geometry_type = ly.geometryType()
        if geometry_type == 0:  # point
            if len(feat) == 3:
                ver = [f.geometry().vertexAt(0) for f in feat]
            else:
                self.msg('Hay que seleccionar 3 puntos')
        elif geometry_type == 2:  #polygon
            if len(feat) == 1:
                geom = feat[0].geometry()
                ver = list(geom.vertices())
                if len(ver) == 4:
                    ver = ver[:3]
                else:
                    self.msg('El polígono tiene que ser un triángulo')
            else:
                self.msg('Seleccionar solo un triángulo')
        else:
            self.msg('seleccionar tres puntos o un triángulo')
        if ver:
            self.planeCalc = PlaneCalc(ver)
            self.info(
                'Selecciona los elementos de una capa para calcular su Z en el plano'
            )
            self.calc_z.setEnabled(True)
            self.setHighlight(ly, ver)
        else:
            self.planeCalc = None
            self.calc_z.setEnabled(False)

    def calcZ(self):

        layer = self.iface.activeLayer()
        if not layer:
            QMessageBox.warning(None, 'TIN Tools',
                                'Selecciona elemenos de una capa')
            return
        if not layer.isEditable():
            QMessageBox.information(None, 'TIN cal',
                                    'La capa no está en modo edición')
            return
        for f in layer.getSelectedFeatures():
            geom = f.geometry()
            n = 0
            v = geom.vertexAt(0)
            while (v != QgsPoint(0, 0)):
                z = self.planeCalc.cal_z(v.x(), v.y())
                v.setZ(z)
                geom.moveVertex(v, n)
                n += 1
                v = geom.vertexAt(n)
            layer.changeGeometry(f.id(), geom)

    def adjustToTin(self):
        print('calc tin')
pr.addAttributes([
    QgsField("name", QVariant.String),
    QgsField("age", QVariant.Int),
    QgsField("size", QVariant.Double)
])
vl.updateFields()  # tell the vector layer to fetch changes from the provider

infos = [[10, 10, "John", 24, 1.73], [40, -60, "Paul", 29, 1.86],
         [60, 5, "George", 34, 1.69], [0, 45, "Ringo", 73, 1.75]]

# add features
for i in infos:
    fet = QgsFeature()
    fet.setGeometry(QgsGeometry.fromPoint(QgsPoint(i[0], i[1])))
    fet.setAttributes(i[2:5])
    pr.addFeatures([fet])

# update layer's extent when new features have been added
# because change of extent in provider is not propagated to the layer
vl.updateExtents()

QgsMapLayerRegistry.instance().addMapLayer(vl)

highlight = QgsHighlight(iface.mapCanvas(),
                         QgsGeometry.fromPoint(QgsPoint(0, 47)), vl)
highlight.setBuffer(1.5)
highlight.setColor(QColor('black'))
highlight.setFillColor(QColor('blue'))
highlight.setWidth(0.5)
iface.mapCanvas().refresh()
Exemplo n.º 35
0
class DetailsTreeView(DetailsDBHandler, DetailsDockWidget):
    def __init__(self, iface, spatial_unit_dock):

        """
        The method initializes the dockwidget.
        :param iface: QGIS user interface class
        :type class qgis.utils.iface
        :param plugin: The STDM plugin
        :type class
        :return: None
        """
        from stdm.ui.entity_browser import _EntityDocumentViewerHandler
        DetailsDockWidget.__init__(self, iface, spatial_unit_dock)

        DetailsDBHandler.__init__(self)

        self.spatial_unit_dock = spatial_unit_dock

        self.view = QTreeView()
        self.view.setSelectionBehavior(
            QAbstractItemView.SelectRows
        )
        #self.feature_ids = []
        self.layer_table = None
        self.entity = None
        self.feature_models = {}
        self.party_models = {}
        self.STR_models = {}
        self.feature_STR_model = {}
        self.removed_feature = None
        self.selected_root = None
        self.model = QStandardItemModel()
        self.view.setModel(self.model)
        self.view.setUniformRowHeights(True)
        self.view.setRootIsDecorated(True)
        self.view.setAlternatingRowColors(True)
        self.view.setWordWrap(True)
        self.view.setHeaderHidden(True)
        self.view.setEditTriggers(
            QAbstractItemView.NoEditTriggers
        )
        self.current_profile = current_profile()
        self.social_tenure = self.current_profile.social_tenure
        self.spatial_unit = self.social_tenure.spatial_unit
        self.party = self.social_tenure.party
        self.view.setMinimumWidth(250)
        self.doc_viewer_title = QApplication.translate(
            'EntityBrowser',
            'Document Viewer'
        )
        self.doc_viewer = _EntityDocumentViewerHandler(
            self.doc_viewer_title, self.iface.mainWindow()
        )

    def set_layer_entity(self):
        self.layer_table = self.get_layer_source(
            self.iface.activeLayer()
        )
        if self.layer_table in spatial_tables():
            self.entity = self.current_profile.entity_by_name(
                self.layer_table
            )

        else:
            self.treeview_error('The layer is not a spatial entity layer. ')

    def activate_feature_details(self, button_clicked=True):
        """
        Action for showing feature details.
        :return:
        """
        # Get the active layer.
        active_layer = self.iface.activeLayer()
        # TODO fix feature_details_btn is deleted error.
        if active_layer is not None and \
                self.spatial_unit_dock.feature_details_btn.isChecked():
            # if feature detail dock is not defined or hidden, create empty dock.
            if self is None or self.isHidden():
                # if the selected layer is not a feature layer, show not
                # feature layer. (implicitly included in the if statement).
                if not self.feature_layer(active_layer):
                    self.spatial_unit_dock.feature_details_btn.setChecked(False)
                    return
                # If the selected layer is feature layer, get data and
                # display treeview in a dock widget
                else:
                    select_feature = QApplication.translate(
                        "STDMQGISLoader",
                        "Please select a feature to view their details."
                    )
                    self.init_dock()
                    self.add_tree_view()
                    self.model.clear()
                    self.treeview_error(select_feature)

                    # enable the select tool
                    self.activate_select_tool()
                    # set entity from active layer in the child class
                    self.set_layer_entity()
                    # set entity for the super class DetailModel
                    self.set_entity(self.entity)
                    # Registery column widget
                    self.set_formatter()
                    #set formatter for social tenure relationship.
                    self.set_formatter(self.social_tenure)
                    self.set_formatter(self.party)
                    # pull data, show treeview
                    active_layer.selectionChanged.connect(
                        self.show_tree
                    )
                    self.steam_signals(self.entity)

            # if feature_detail dock is open, toggle close
            else:
                self.close_dock(
                    self.spatial_unit_dock.feature_details_btn
                )
                self.feature_details = None
        # if no active layer, show error message and uncheck the feature tool
        else:
            if button_clicked:
                self.active_layer_check()
            self.spatial_unit_dock.feature_details_btn.setChecked(False)

    def add_tree_view(self):
        """
        Adds tree view to the dock widget and sets style.
        :return: None
        """
        self.tree_scrollArea.setWidget(self.view)

    def clear_feature_models(self):
        self.feature_models.clear()

    def reset_tree_view(self, no_feature=False):
        #clear feature_ids list, model and highlight
        self.model.clear()

        self.clear_sel_highlight() # remove sel_highlight
        self.disable_buttons(no_feature)
        if self.removed_feature is None:
            self.STR_models.clear()
            self.feature_models.clear()
        else:
            self.removed_feature = None
        features = self.selected_features()
        # if the selected feature is over 1,
        # activate multi_select_highlight
        if not features is None:
            self.view.clicked.connect(
                self.multi_select_highlight
            )
        # if there is at least one selected feature
        if len(features) > 0:
            self.add_tree_view()
            #self.feature_ids = features

    def disable_buttons(self, bool):
        self.edit_btn.setDisabled(bool)
        self.delete_btn.setDisabled(bool)

    def show_tree(self):
        selected_features = self.selected_features()
        if len(selected_features) < 1:
            self.reset_tree_view(True)
            return
        if not self.entity is None:
            self.reset_tree_view()
            if len(selected_features) < 1:
                self.disable_buttons(True)
                return

            layer_icon = QIcon(':/plugins/stdm/images/icons/layer.gif')
            roots = self.add_parent_tree(
                layer_icon, format_name(self.entity.short_name)
            )
            if roots is None:
                return

            for id, root in roots.iteritems():
                db_model = entity_id_to_model(self.entity, id)

                self.add_roots(db_model, root, id)

    def add_parent_tree(self, icon, title):
        roots = OrderedDict()
        for feature_id in self.selected_features():
            root = QStandardItem(icon, title)
            root.setData(feature_id)
            self.set_bold(root)
            self.model.appendRow(root)
            roots[feature_id] = root
        return roots

    def add_roots(self, model, parent, feature_id):
        self.feature_models[feature_id] = model
        if model is None:
            return
        self.column_widget_registry(model, self.entity)

        for i, (col, row) in enumerate(self.formatted_record.iteritems()):
            child = QStandardItem('{}: {}'.format(col, row))
            child.setSelectable(False)
            parent.appendRow([child])

            # Add Social Tenure Relationship steam as a last child
            if i == len(self.formatted_record)-1:
                self.add_STR_child(parent, feature_id)
        self.expand_node(parent)

    def add_STR_steam(self, parent, STR_id):
        str_icon = QIcon(
            ':/plugins/stdm/images/icons/social_tenure.png'
        )
        title = 'Social Tenure Relationship'
        str_root = QStandardItem(str_icon, title)
        str_root.setData(STR_id)
        self.set_bold(str_root)
        parent.appendRow([str_root])
        return str_root
    def add_no_STR_steam(self, parent):
        if self.entity.name == self.spatial_unit.name:
            no_str_icon = QIcon(
                ':/plugins/stdm/images/icons/remove.png'
            )
            title = 'No STR Defined'
            no_str_root = QStandardItem(no_str_icon, title)
            self.set_bold(no_str_root)
            parent.appendRow([no_str_root])

    def add_STR_child(self, parent, feature_id):
        if len(self.feature_STR_link(feature_id)) < 1:
            self.add_no_STR_steam(parent)
            return
        for record in self.feature_STR_link(feature_id):
            self.STR_models[record.id] = record
            str_root = self.add_STR_steam(parent, record.id)
            # add STR children
            self.column_widget_registry(record, self.social_tenure)
            for i, (col, row) in enumerate(
                    self.formatted_record.iteritems()
            ):
                STR_child = QStandardItem(
                    '{}: {}'.format(col, row)
                )
                STR_child.setSelectable(False)
                str_root.appendRow([STR_child])
                if i == len(self.formatted_record)-1:
                    self.add_party_child(
                        str_root, record.party_id
                    )
        self.feature_STR_model[feature_id] = self.STR_models.keys()

    def add_party_steam(self, parent, party_id):
        party_icon = QIcon(
            ':/plugins/stdm/images/icons/table.png'
        )
        title = format_name(self.party.short_name)
        party_root = QStandardItem(party_icon, title)
        party_root.setData(party_id)
        self.set_bold(party_root)

        parent.appendRow([party_root])
        party_root.setEditable(False)
        return party_root

    def add_party_child(self, parent, party_id):

        db_model = entity_id_to_model(self.party, party_id)
        self.party_models[party_id] = db_model
        party_root = self.add_party_steam(parent, party_id)
        # add STR children
        self.column_widget_registry(db_model, self.party)
        for col, row in self.formatted_record.iteritems():
            party_child = QStandardItem('{}: {}'.format(col, row))
            party_child.setSelectable(False)
            party_root.appendRow([party_child])

    def set_bold(self, standard_item):
        """
        Make a text of Qstandaritem to bold.
        :param standard_item: Qstandaritem
        :type: Qstandaritem
        :return: None
        """
        font = standard_item.font()
        font.setBold(True)
        standard_item.setFont(font)

    def treeview_error(self, message, icon=None):
        """
        Displays error message in feature details treeview.
        :param title: the title of the treeview.
        :type: String
        :param message: The message to be displayed.
        :type: String
        :param icon: The icon of the item.
        :type: Resource string
        :return: None
        """
        not_feature_ft_msg = QApplication.translate(
            'FeatureDetails', message
        )
        if icon== None:
            root = QStandardItem(not_feature_ft_msg)
        else:
            root = QStandardItem(icon, not_feature_ft_msg)

        self.view.setRootIsDecorated(False)
        self.model.appendRow(root)
        self.view.setRootIsDecorated(True)

    def expand_node(self, parent):
        """
        Make the last tree node expand.
        :param parent: The parent to expand
        :type QStandardItem
        :return:None
        """
        index = self.model.indexFromItem(parent)
        self.view.expand(index)


    def multi_select_highlight(self, index):
        """
        Highlights a feature with rubberBald class when selecting
        features are more than one.
        :param index: Selected QTreeView item index
        :type Integer
        :return: None
        """
        map = self.iface.mapCanvas()
        try:

            # Get the selected item text using the index
            selected_item = self.model.itemFromIndex(index)
            # Use mutli-select only when more than 1 items are selected.
            if self.layer.selectedFeatures() < 2:
                return
            self.selected_root = selected_item
            # Split the text to get the key and value.
            selected_item_text = selected_item.text()

            selected_value = selected_item.data()
            # If the first word is feature, expand & highlight.
            if selected_item_text == format_name(self.spatial_unit.short_name):
                self.view.expand(index)  # expand the item
                # Clear any existing highlight
                self.clear_sel_highlight()
                # Insert highlight
                # Create expression to target the selected feature
                expression = QgsExpression(
                    "\"id\"='" + str(selected_value) + "'"
                )
                # Get feature iteration based on the expression
                ft_iteration = self.layer.getFeatures(
                    QgsFeatureRequest(expression)
                )

                # Retrieve geometry and attributes
                for feature in ft_iteration:
                    # Fetch geometry
                    geom = feature.geometry()
                    self.sel_highlight = QgsHighlight(map, geom, self.layer)

                    self.sel_highlight.setFillColor(selection_color())
                    self.sel_highlight.setWidth(4)
                    self.sel_highlight.setColor(QColor(212,95,0, 255))
                    self.sel_highlight.show()
                    break
        except AttributeError:
            # pass attribute error on child items such as party
            pass
        except IndexError:
            pass

    def steam_signals(self, entity):
        self.edit_btn.clicked.connect(
            lambda : self.edit_selected_steam(
                entity
            )
        )
        self.delete_btn.clicked.connect(
            self.delete_selected_item
        )
        self.view_document_btn.clicked.connect(
            lambda : self.view_steam_document(
                entity
            )
        )

    def steam_data(self, mode):
        item = None
        # if self.view.currentIndex().text() == format_name(self.party):
        #     return None, None
        # One item is selected and number of feature is also 1
        if len(self.layer.selectedFeatures()) == 1 and \
                        len(self.view.selectedIndexes()) == 1:
            index = self.view.selectedIndexes()[0]
            item = self.model.itemFromIndex(index)
            result = item.data()

        # One item is selected on the map but not on the treeview
        elif len(self.layer.selectedFeatures()) == 1 and \
                        len(self.view.selectedIndexes()) == 0:
            item = self.model.item(0, 0)
            result = item.data()

        # multiple features are selected but one treeview item is selected
        elif len(self.layer.selectedFeatures()) > 1 and \
                        len(self.view.selectedIndexes()) == 1:
            item = self.selected_root
            result = self.selected_root.data()
        # multiple features are selected but no treeview item is selected
        elif len(self.layer.selectedFeatures()) > 1 and \
             len(self.view.selectedIndexes()) == 0:
            result = 'Please, select an item to {}.'.format(mode)
        else:
            result = 'Please, select at least one feature to {}.'.format(mode)
        if result is None:

            if item is None:
                item = self.model.item(0, 0)
                result = item.data()
            else:
                result = item.parent().data()
        return result, item

    def edit_selected_steam(self, entity):
        id, item = self.steam_data('edit')

        feature_edit = True
        if id is None:
            return
        if isinstance(id, str):
            data_error = QApplication.translate('DetailsTreeView', id)
            QMessageBox.warning(
                self.iface.mainWindow(), "Edit Error", data_error
            )
            return

        if item.text() == 'Social Tenure Relationship':
            model = self.STR_models[id]

            feature_edit = False
            ##TODO add STR wizard edit mode here.
        elif item.text() == format_name(self.party.short_name):
            feature_edit = False

            model = self.party_models[id]
            editor = EntityEditorDialog(
                self.party, model, self.iface.mainWindow()
            )
            editor.exec_()
        else:
            model = self.feature_models[id]

            editor = EntityEditorDialog(
                entity, model, self.iface.mainWindow()
            )
            editor.exec_()
        #root = self.find_root(entity, id)
        self.view.expand(item.index())
        if feature_edit:
            self.update_edited_steam(entity, id)
        else:
            self.update_edited_steam(self.social_tenure, id)

    def delete_selected_item(self):
        str_edit = False
        id, item = self.steam_data('delete')

        if isinstance(id, str):
            data_error = QApplication.translate(
                'DetailsTreeView', id
            )
            QMessageBox.warning(
                self.iface.mainWindow(),
                'Delete Error',
                data_error
            )
            return
        if item.text() == 'Social Tenure Relationship':
            str_edit = True
            db_model = self.STR_models[id]

        elif item.text() == format_name(self.spatial_unit.short_name) and \
            id not in self.feature_STR_model.keys():
            db_model = self.feature_models[id]

        # if spatial unit is linked to STR, don't allow delete
        elif item.text() == format_name(self.spatial_unit.short_name) and \
                        id in self.feature_STR_model.keys():


            delete_warning = QApplication.translate(
                'DetailsTreeView',
                'You have to first delete the social tenure \n'
                'relationship to delete the {} record.'.format(
                    item.text()
                )

            )
            QMessageBox.warning(
                self.iface.mainWindow(),
                'Delete Error',
                delete_warning
            )
            return
        # If it is party node, STR exists and don't allow delete.
        elif item.text() == format_name(self.party.short_name):
            delete_warning = QApplication.translate(
                'DetailsTreeView',
                'You have to first delete the social tenure \n'
                'relationship to delete the {} record.'.format(
                    item.text()
                )
            )
            QMessageBox.warning(
                self.iface.mainWindow(),
                'Delete Error',
                delete_warning
            )
            return
        else:
            return
        delete_warning = QApplication.translate(
            'DetailsTreeView',
            'Are you sure you want to delete '
            'the selected record(s)?\n'
            'This action cannot be undone.'
        )

        delete_question = QMessageBox.warning(
            self.iface.mainWindow(),
            "Delete Warning",
            delete_warning,
            QMessageBox.Yes | QMessageBox.No
        )
        if delete_question == QMessageBox.Yes:
            db_model.delete()

            if str_edit:
                del self.STR_models[id]
            else:
                self.removed_feature = id
                del self.feature_models[id]

            self.updated_removed_steam(str_edit, item)
        else:
            return

    def update_edited_steam(self, entity, feature_id):

        # remove rows before adding the updated ones.
        self.layer.setSelectedFeatures(
            self.feature_models.keys()
        )
        root = self.find_root(entity, feature_id)
        if root is None:
            return
        self.view.selectionModel().select(
            root.index(), self.view.selectionModel().Select
        )
        self.expand_node(root)
        self.multi_select_highlight(root.index())

    def find_root(self, entity, feature_id):
        all_roots = self.model.findItems(
            format_name(entity.short_name)
        )
        root = None
        for item in all_roots:
            if item.data() == feature_id:
                root = item
                break
        return root

    def updated_removed_steam(self, STR_edit, item):
        if not STR_edit:
            if len(self.feature_models) > 1:
                self.refresh_layers()
            feature_ids = self.feature_models.keys()
            self.layer.setSelectedFeatures(
                feature_ids
            )
        else:
            item.removeRows(0, 2)
            item.setText('No STR Definded')
            no_str_icon = QIcon(
                ':/plugins/stdm/images/icons/remove.png'
            )
            item.setIcon(no_str_icon)

    def view_steam_document(self, entity):
        # Slot raised to show the document viewer for the selected entity

        id, item = self.steam_data('edit')

        if id is None:
            return
        if isinstance(id, str):
            data_error = QApplication.translate('DetailsTreeView', id)
            QMessageBox.warning(
                self.iface.mainWindow(), "Edit Error", data_error
            )
            return
        if item.text() == 'Social Tenure Relationship':
            db_model = self.STR_models[id]
        else:
            db_model = self.feature_models[id]

        if not db_model is None:
            docs = db_model.documents
            # Notify there are no documents for the selected doc
            if len(docs) == 0:
                msg = QApplication.translate(
                    'EntityBrowser',
                    'There are no supporting documents '
                    'for the selected record.'
                )

                QMessageBox.warning(
                    self,
                    self.doc_viewer_title,
                    msg
                )
            else:
                self.doc_viewer.load(docs)
Exemplo n.º 36
0
class SpatialPreview(QTabWidget, Ui_frmPropertyPreview):
    """
    Widget for previewing spatial unit on either local map or web source.
    """
    def __init__(self, parent=None, iface=None):
        QTabWidget.__init__(self, parent)
        self.setupUi(self)

        self._notif_bar = None
        self._ol_loaded = False
        self._overlay_layer = None
        self.sel_highlight = None
        self.memory_layer = None
        self._db_session = STDMDb.instance().session

        self.set_iface(iface)

        #Web config
        self._web_spatial_loader = WebSpatialLoader(self.spatial_web_view,
                                                    self)

        #Connect signals
        self._web_spatial_loader.loadError.connect(
            self.on_spatial_browser_error)
        self._web_spatial_loader.loadProgress.connect(
            self.on_spatial_browser_loading)
        self._web_spatial_loader.loadFinished.connect(
            self.on_spatial_browser_finished)
        self._web_spatial_loader.zoomChanged.connect(
            self.on_map_zoom_level_changed)
        self.rbGMaps.toggled.connect(self.on_load_GMaps)
        self.rbOSM.toggled.connect(self.on_load_OSM)
        self.zoomSlider.sliderReleased.connect(self.on_zoom_changed)
        self.btnResetMap.clicked.connect(self.on_reset_web_map)
        self.btnSync.clicked.connect(self.on_sync_extents)
        QgsMapLayerRegistry.instance().layersWillBeRemoved.connect(
            self._on_overlay_to_be_removed)

    def set_iface(self, iface):
        self._iface = iface
        self.local_map.set_iface(iface)

    def set_notification_bar(self, notif_bar):
        """
        Set notification widget.
        :param notif_bar: Notification widget.
        """
        self._notif_bar = notif_bar

    def notification_bar(self):
        """
        :return: Currently configured notification bar.
        """
        return self._notif_bar

    def _insert_notification(self, msg, level, clear_first=True):
        if self._notif_bar is None:
            return

        if clear_first:
            self._notif_bar.clear()

        self._notif_bar.insertNotification(msg, level)

    def iface(self):
        return self._iface

    def _setDefaults(self):
        """
        Set default settings
        """
        self.set_canvas_background_color(self.canvasBgColor)

    def set_canvas_background_color(self, color):
        """
        Set the background color of the map canvas
        """
        self.localMap.setCanvasColor(color)
        self.canvasBgColor = color

    def refresh_canvas_layers(self, process_events=False):
        """
        Reload map layers in the viewer canvas.
        """
        self.local_map.refresh_layers()

    def load_web_map(self):
        """
        Loads the web map into the view using canvas extents if there
        are existing layers in the map canvas.
        """
        if not self._ol_loaded:
            self._web_spatial_loader.load()

    def _create_vector_layer(self, geom_type, prj_code):
        """
        Creates/resets the internal vector layer that will be used to draw
        the spatial unit overlays.
        :param geom_type: Geometry type
        :type geom_type: str
        :param prj_code: EPSG code
        :type prj_code: int
        """
        self._overlay_layer = QgsVectorLayer(
            u"{0}?crs=epsg:{1!s}&field=lbname:string(20)&index=yes".format(
                geom_type, prj_code), "view_str_spatial_unit", "memory")

    def draw_spatial_unit(self, spatial_unit, model):
        """
        Draw geometry of the given model in the respective local and web views.
        :param model: Source model whose geometry will be drawn.
        :type model: object
        :param clear_existing: Clears any existing features prior to adding the
        new features.
        :type clear_existing: bool
        """
        if model is None:
            msg = QApplication.translate(
                "SpatialPreview", "Data model is empty, the spatial "
                "unit cannot be rendered.")
            QMessageBox.critical(
                self,
                QApplication.translate("SpatialPreview",
                                       "Spatial Unit Preview"), msg)

            return

        table_name = spatial_unit.name
        if not pg_table_exists(table_name):
            msg = QApplication.translate(
                "SpatialPreview", "The spatial unit data source could "
                "not be retrieved, the feature cannot "
                "be rendered.")
            QMessageBox.critical(
                self,
                QApplication.translate("SpatialPreview",
                                       "Spatial Unit Preview"), msg)

            return

        sp_unit_manager = SpatialUnitManagerDockWidget(self.iface())
        spatial_cols = sp_unit_manager.geom_columns(spatial_unit)

        geom, geom_col = None, ""
        sc_obj = None
        for sc in spatial_cols:

            db_geom = getattr(model, sc.name)
            #Use the first non-empty geometry
            # value in the collection
            if not db_geom is None:
                sc_obj = sc
                geom_col = sc.name
                geom = db_geom
        QApplication.processEvents()

        lyr = sp_unit_manager.geom_col_layer_name(table_name, sc_obj)

        sp_unit_manager.add_layer_by_name(lyr)

        if geom is not None:

            self.highlight_spatial_unit(spatial_unit, geom,
                                        self.local_map.canvas)
            self._web_spatial_loader.add_overlay(model, geom_col)

    def clear_sel_highlight(self):
        """
        Removes sel_highlight from the canvas.
        :return:
        """
        if self.sel_highlight is not None:
            self.sel_highlight = None

    def get_layer_source(self, layer):
        """
        Get the layer table name if the source is from the database.
        :param layer: The layer for which the source is checked
        :type QGIS vectorlayer
        :return: String or None
        """
        source = layer.source()
        vals = dict(re.findall('(\S+)="?(.*?)"? ', source))
        try:
            table = vals['table'].split('.')
            table_name = table[1].strip('"')
            return table_name
        except KeyError:
            return None

    def spatial_unit_layer(self, spatial_unit, active_layer):
        """
        Check whether the layer is parcel layer or not.
        :param active_layer: The layer to be checked
        :type QGIS vectorlayer
        :return: Boolean
        """
        if self.active_layer_check():
            layers = self.iface().legendInterface().layers()

            for layer in layers:
                layer_source = self.get_layer_source(layer)
                if layer_source == spatial_unit.name:
                    self.iface().setActiveLayer(layer)
                    return True

            not_sp_msg = QApplication.translate(
                'SpatialPreview',
                'You have selected a non-spatial_unit layer. '
                'Please select a spatial unit layer to preview.')
            QMessageBox.information(self._iface.mainWindow(), "Error",
                                    not_sp_msg)

    def active_layer_check(self):
        """
        Check if there is active layer and if not, displays
        a message box to select a parcel layer.
        :return:
        """
        active_layer = self._iface.activeLayer()
        if active_layer is None:
            no_layer_msg = QApplication.translate(
                'SpatialPreview', 'Please add a spatial unit layer '
                'to preview the spatial unit.')
            QMessageBox.critical(self._iface.mainWindow(), "Error",
                                 no_layer_msg)
            return False
        else:
            return True

    def _add_geom_to_map(self, geom):

        if self._overlay_layer is None:
            return

        geom_func = geom.ST_AsText()
        geom_wkt = self._db_session.scalar(geom_func)

        dp = self._overlay_layer.dataProvider()

        feat = QgsFeature()
        qgis_geom = QgsGeometry.fromWkt(geom_wkt)
        feat.setGeometry(g)
        dp.addFeatures([feat])

        self._overlay_layer.updateExtents()

        return qgis_geom.boundingBox()

    def highlight_spatial_unit(self, spatial_unit, geom, map_canvas):
        layer = self._iface.activeLayer()
        map_canvas.setExtent(layer.extent())
        map_canvas.refresh()

        if self.spatial_unit_layer(spatial_unit, layer):

            self.clear_sel_highlight()

            qgis_geom = qgsgeometry_from_wkbelement(geom)

            self.sel_highlight = QgsHighlight(map_canvas, qgis_geom, layer)
            rgba = selection_color()
            self.sel_highlight.setFillColor(rgba)

            self.sel_highlight.setWidth(3)
            self.sel_highlight.show()

            extent = qgis_geom.boundingBox()
            extent.scale(1.5)
            map_canvas.setExtent(extent)
            map_canvas.refresh()
        else:
            return

    def remove_preview_layer(self, layer, name):
        """
        Removes the preview layer from legend.
        :param layer: The preview polygon layer to be removed.
        :param name: The name of the layer to be removed.
        :return: None
        """
        if layer is not None:
            for lyr in QgsMapLayerRegistry.instance().mapLayers().values():
                if lyr.name() == name:
                    id = lyr.id()
                    QgsMapLayerRegistry.instance().removeMapLayer(id)

    def delete_local_features(self, feature_ids=[]):
        """
        Removes features in the local map overlay.
        """
        del_status = False

        if not self._overlay_layer is None:
            if len(feature_ids) == 0:
                feature_ids = self._overlay_layer.allFeatureIds()

            del_status = self._overlay_layer.dataProvider().deleteFeatures(
                feature_ids)

        return del_status

    def remove_layer(self):
        """
        Removes both the local and web layers.
        """
        if not self._overlay_layer is None:
            QgsProject.instance().layerTreeRoot().removeLayer(
                self._overlay_layer)

            #Clear web overlays
            self._web_spatial_loader.removeOverlay()

            self._overlay_layer = None

    def _on_overlay_to_be_removed(self, layers_ids):
        """
        Resets the local layer variable and removes the web overlay.
        """
        if not self._overlay_layer is None:
            if self._overlay_layer.id() in layers_ids:
                self.remove_layer()

    def on_spatial_browser_error(self, err):
        """
        Slot raised when an error occurs when loading items in the property browser
        """
        self._insert_notification(err, ERROR)

    def on_spatial_browser_loading(self, progress):
        """
        Slot raised when the property browser is loading.
        Displays the progress of the page loading as a percentage.
        """
        if progress <= 0 or progress >= 100:
            self.lblInfo.setText("")
            self.lblInfo.setVisible(False)

        else:
            self.lblInfo.setVisible(True)
            self.lblInfo.setText("Loading...%d%%)" % (progress))

    def on_spatial_browser_finished(self, status):
        """
        Slot raised when the property browser finishes loading the content
        """
        if status:
            if len(self.local_map.canvas_layers()
                   ) > 0:  # and not self._ol_loaded:
                self.on_sync_extents()

            self._ol_loaded = True
            #self._overlay_spatial_unit()

        else:
            msg = QApplication.translate(
                "SpatialPreview", "Error: Spatial unit cannot be loaded.")
            self._insert_notification(msg, ERROR)

    def on_zoom_changed(self):
        """
        Slot raised when the zoom value in the slider changes.
        This is only raised once the user releases the slider with the mouse.
        """
        zoom = self.zoomSlider.value()
        self._web_spatial_loader.zoom_to_level(zoom)

    def on_load_GMaps(self, state):
        """
        Slot raised when a user clicks to set Google Maps Satellite
        as the base layer
        """
        if state:
            self._web_spatial_loader.setBaseLayer(GMAP_SATELLITE)

    def on_load_OSM(self, state):
        """
        Slot raised when a user clicks to set OSM as the base layer
        """
        if state:
            self._web_spatial_loader.setBaseLayer(OSM)

    def on_map_zoom_level_changed(self, level):
        """
        Slot which is raised when the zoom level of the map changes.
        """
        self.zoomSlider.setValue(level)

    def on_reset_web_map(self):
        """
        Slot raised when the user clicks to reset the property
        location in the map.
        """
        self._web_spatial_loader.zoom_to_extents()

    def on_sync_extents(self):
        """
        Slot raised to synchronize the webview extents with those of the
        local map canvas.
        """
        if len(self.local_map.canvas_layers()) > 0:  # and self._ol_loaded:
            curr_extent = self.map_extents()
            self._web_spatial_loader.zoom_to_map_extents(curr_extent)

    def map_extents(self):
        """
        :returns: Current extents of the local map.
        :rtype: QgsRectangle
        """
        return self.local_map.extent()

    def canvas_zoom_to_extent(self, extent):
        self.local_map.canvas.setExtent(extent)
Exemplo n.º 37
0
class FeatureSelectorWidget(QWidget):
    feature_identified = pyqtSignal(QgsFeature)

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

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

        self.line_edit = QLineEdit(self)
        self.line_edit.setReadOnly(True)
        edit_layout.addWidget(self.line_edit)

        self.highlight_feature_button = QToolButton(self)
        self.highlight_feature_button.setPopupMode(QToolButton.MenuButtonPopup)
        self.highlight_feature_action = QAction(
            QgsApplication.getThemeIcon("/mActionHighlightFeature.svg"),
            "Highlight feature", self)
        self.scale_highlight_feature_action = QAction(
            QgsApplication.getThemeIcon("/mActionScaleHighlightFeature.svg"),
            "Scale and highlight feature", self)
        self.pan_highlight_feature_action = QAction(
            QgsApplication.getThemeIcon("/mActionPanHighlightFeature.svg"),
            "Pan and highlight feature", self)
        self.highlight_feature_button.addAction(self.highlight_feature_action)
        self.highlight_feature_button.addAction(
            self.scale_highlight_feature_action)
        self.highlight_feature_button.addAction(
            self.pan_highlight_feature_action)
        self.highlight_feature_button.setDefaultAction(
            self.highlight_feature_action)
        edit_layout.addWidget(self.highlight_feature_button)

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

        self.map_identification_button.clicked.connect(self.map_identification)
        self.highlight_feature_button.triggered.connect(
            self.highlight_action_triggered)

        self.layer = None
        self.map_tool = None
        self.canvas = None
        self.window_widget = None
        self.highlight = None
        self.feature = QgsFeature()

    def set_canvas(self, map_canvas):
        self.map_tool = QgsMapToolIdentifyFeature(map_canvas)
        self.map_tool.setButton(self.map_identification_button)
        self.canvas = map_canvas

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

    def set_feature(self, feature, canvas_extent=CanvasExtent.Fixed):
        self.line_edit.clear()
        self.feature = feature

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

        expression = QgsExpression(self.layer.displayExpression())
        context = QgsExpressionContext()
        scope = QgsExpressionContextScope()
        context.appendScope(scope)
        scope.setFeature(feature)
        feature_title = expression.evaluate(context)
        if feature_title == "":
            feature_title = feature.id()
        self.line_edit.setText(str(feature_title))
        self.highlight_feature(canvas_extent)

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

    @pyqtSlot()
    def map_identification(self):
        if self.layer is None or self.map_tool is None or self.canvas is None:
            return

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

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

        self.map_tool.featureIdentified.connect(
            self.map_tool_feature_identified)
        self.map_tool.deactivated.connect(self.map_tool_deactivated)

    def map_tool_feature_identified(self, feature):
        feature = QgsFeature(feature)
        self.feature_identified.emit(feature)
        self.unset_map_tool()
        self.set_feature(feature)

    def map_tool_deactivated(self):
        if self.window_widget is not None:
            self.window_widget.raise_()
            self.window_widget.activateWindow()

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

        geom = self.feature.geometry()

        if geom is None:
            return

        if canvas_extent == CanvasExtent.Scale:
            feature_bounding_box = geom.boundingBox()
            feature_bounding_box = self.canvas.mapSettings(
            ).layerToMapCoordinates(self.layer, feature_bounding_box)
            extent = self.canvas.extent()
            if not extent.contains(feature_bounding_box):
                extent.combineExtentWith(feature_bounding_box)
                extent.scale(1.1)
                self.canvas.setExtent(extent)
                self.canvas.refresh()

        elif canvas_extent == 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 unset_map_tool(self):
        if self.canvas is not None and self.map_tool is not None:
            # this will call mapTool.deactivated
            self.canvas.unsetMapTool(self.map_tool)

    def highlight_action_triggered(self, action):
        self.highlight_feature_button.setDefaultAction(action)

        if action == self.highlight_feature_action:
            self.highlight_feature()

        elif action == self.scale_highlight_feature_action:
            self.highlight_feature(CanvasExtent.Scale)

        elif action == self.pan_highlight_feature_action:
            self.highlight_feature(CanvasExtent.Pan)
Exemplo n.º 38
0
class SpatialPreview(QTabWidget, Ui_frmPropertyPreview):
    """
    Widget for previewing spatial unit on either local map or web source.
    """
    def __init__(self, parent=None, iface=None):
        QTabWidget.__init__(self, parent)
        self.setupUi(self)

        self._notif_bar = None
        self._ol_loaded = False
        self._overlay_layer = None
        self.sel_highlight = None
        self.memory_layer = None
        self._db_session = STDMDb.instance().session

        self.set_iface(iface)

        #Web config
        self._web_spatial_loader = WebSpatialLoader(self.spatial_web_view, self)

        #Connect signals
        self._web_spatial_loader.loadError.connect(self.on_spatial_browser_error)
        self._web_spatial_loader.loadProgress.connect(self.on_spatial_browser_loading)
        self._web_spatial_loader.loadFinished.connect(self.on_spatial_browser_finished)
        self._web_spatial_loader.zoomChanged.connect(self.on_map_zoom_level_changed)
        self.rbGMaps.toggled.connect(self.on_load_GMaps)
        self.rbOSM.toggled.connect(self.on_load_OSM)
        self.zoomSlider.sliderReleased.connect(self.on_zoom_changed)
        self.btnResetMap.clicked.connect(self.on_reset_web_map)
        self.btnSync.clicked.connect(self.on_sync_extents)
        QgsMapLayerRegistry.instance().layersWillBeRemoved.connect(self._on_overlay_to_be_removed)

    def set_iface(self, iface):
        self._iface = iface
        self.local_map.set_iface(iface)

    def set_notification_bar(self, notif_bar):
        """
        Set notification widget.
        :param notif_bar: Notification widget.
        """
        self._notif_bar = notif_bar

    def notification_bar(self):
        """
        :return: Currently configured notification bar.
        """
        return self._notif_bar

    def _insert_notification(self, msg, level, clear_first = True):
        if self._notif_bar is None:
            return

        if clear_first:
            self._notif_bar.clear()

        self._notif_bar.insertNotification(msg, level)

    def iface(self):
        return self._iface

    def _setDefaults(self):
        """
        Set default settings
        """
        self.set_canvas_background_color(self.canvasBgColor)

    def set_canvas_background_color(self,color):
        """
        Set the background color of the map canvas
        """
        self.localMap.setCanvasColor(color)
        self.canvasBgColor = color

    def refresh_canvas_layers(self, process_events=False):
        """
        Reload map layers in the viewer canvas.
        """
        self.local_map.refresh_layers()

    def load_web_map(self):
        """
        Loads the web map into the view using canvas extents if there
        are existing layers in the map canvas.
        """
        if not self._ol_loaded:
            self._web_spatial_loader.load()

    def _create_vector_layer(self, geom_type, prj_code):
        """
        Creates/resets the internal vector layer that will be used to draw
        the spatial unit overlays.
        :param geom_type: Geometry type
        :type geom_type: str
        :param prj_code: EPSG code
        :type prj_code: int
        """
        self._overlay_layer = QgsVectorLayer(
            u"{0}?crs=epsg:{1!s}&field=lbname:string(20)&index=yes".format(geom_type,
                                                                      prj_code),
            "view_str_spatial_unit",
            "memory")

    def draw_spatial_unit(self, spatial_unit, model):
        """
        Draw geometry of the given model in the respective local and web views.
        :param model: Source model whose geometry will be drawn.
        :type model: object
        :param clear_existing: Clears any existing features prior to adding the
        new features.
        :type clear_existing: bool
        """
        if model is None:
            msg = QApplication.translate("SpatialPreview",
                                         "Data model is empty, the spatial "
                                         "unit cannot be rendered.")
            QMessageBox.critical(self,
                                 QApplication.translate(
                                    "SpatialPreview",
                                    "Spatial Unit Preview"),
                                 msg)

            return

        table_name = spatial_unit.name
        if not pg_table_exists(table_name):
            msg = QApplication.translate("SpatialPreview",
                                         "The spatial unit data source could "
                                         "not be retrieved, the feature cannot "
                                         "be rendered.")
            QMessageBox.critical(
                self,
                QApplication.translate(
                    "SpatialPreview",
                    "Spatial Unit Preview"),
                msg
            )

            return

        sp_unit_manager = SpatialUnitManagerDockWidget(self.iface())
        spatial_cols = sp_unit_manager.geom_columns(spatial_unit)

        geom, geom_col = None, ""
        sc_obj = None
        for sc in spatial_cols:

            db_geom = getattr(model, sc.name)
            #Use the first non-empty geometry
            # value in the collection
            if not db_geom is None:
                sc_obj = sc
                geom_col = sc.name
                geom = db_geom
        QApplication.processEvents()

        lyr = sp_unit_manager.geom_col_layer_name(
            table_name, sc_obj
        )

        sp_unit_manager.add_layer_by_name(lyr)

        if geom is not None:

            self.highlight_spatial_unit(
                spatial_unit, geom, self.local_map.canvas
            )
            self._web_spatial_loader.add_overlay(
                model, geom_col
            )

    def clear_sel_highlight(self):
        """
        Removes sel_highlight from the canvas.
        :return:
        """
        if self.sel_highlight is not None:
            self.sel_highlight = None

    def get_layer_source(self, layer):
        """
        Get the layer table name if the source is from the database.
        :param layer: The layer for which the source is checked
        :type QGIS vectorlayer
        :return: String or None
        """
        source = layer.source()
        vals = dict(re.findall('(\S+)="?(.*?)"? ', source))
        try:
            table = vals['table'].split('.')
            table_name = table[1].strip('"')
            return table_name
        except KeyError:
            return None

    def spatial_unit_layer(self, spatial_unit, active_layer):
        """
        Check whether the layer is parcel layer or not.
        :param active_layer: The layer to be checked
        :type QGIS vectorlayer
        :return: Boolean
        """
        if self.active_layer_check():
            layers = self.iface().legendInterface().layers()

            for layer in layers:
                layer_source = self.get_layer_source(layer)
                if layer_source == spatial_unit.name:
                    self.iface().setActiveLayer(layer)
                    return True

            not_sp_msg = QApplication.translate(
                'SpatialPreview',
                'You have selected a non-spatial_unit layer. '
                'Please select a spatial unit layer to preview.'
            )
            QMessageBox.information(
                self._iface.mainWindow(),
                "Error",
                not_sp_msg
            )


    def active_layer_check(self):
        """
        Check if there is active layer and if not, displays
        a message box to select a parcel layer.
        :return:
        """
        active_layer = self._iface.activeLayer()
        if active_layer is None:
            no_layer_msg = QApplication.translate(
                'SpatialPreview',
                'Please add a spatial unit layer '
                'to preview the spatial unit.'
            )
            QMessageBox.critical(
                self._iface.mainWindow(),
                "Error",
                no_layer_msg
            )
            return False
        else:
            return True

    def _add_geom_to_map(self, geom):

        if self._overlay_layer is None:
            return

        geom_func = geom.ST_AsText()
        geom_wkt = self._db_session.scalar(geom_func)

        dp = self._overlay_layer.dataProvider()

        feat = QgsFeature()
        qgis_geom = QgsGeometry.fromWkt(geom_wkt)
        feat.setGeometry(g)
        dp.addFeatures([feat])

        self._overlay_layer.updateExtents()

        return qgis_geom.boundingBox()

    def highlight_spatial_unit(
            self, spatial_unit, geom, map_canvas
    ):
        layer = self._iface.activeLayer()
        map_canvas.setExtent(layer.extent())
        map_canvas.refresh()

        if self.spatial_unit_layer(spatial_unit, layer):

            self.clear_sel_highlight()

            qgis_geom = qgsgeometry_from_wkbelement(geom)

            self.sel_highlight = QgsHighlight(
                map_canvas, qgis_geom, layer
            )
            rgba = selection_color()
            self.sel_highlight.setFillColor(rgba)

            self.sel_highlight.setWidth(3)
            self.sel_highlight.show()

            extent = qgis_geom.boundingBox()
            extent.scale(1.5)
            map_canvas.setExtent(extent)
            map_canvas.refresh()
        else:
            return


    def remove_preview_layer(self, layer, name):
        """
        Removes the preview layer from legend.
        :param layer: The preview polygon layer to be removed.
        :param name: The name of the layer to be removed.
        :return: None
        """
        if layer is not None:
            for lyr in QgsMapLayerRegistry.instance().mapLayers().values():
                if lyr.name() == name:
                    id = lyr.id()
                    QgsMapLayerRegistry.instance().removeMapLayer(id)


    def delete_local_features(self, feature_ids=[]):
        """
        Removes features in the local map overlay.
        """
        del_status = False

        if not self._overlay_layer is None:
            if len(feature_ids) == 0:
                feature_ids = self._overlay_layer.allFeatureIds()

            del_status = self._overlay_layer.dataProvider().deleteFeatures(feature_ids)

        return del_status

    def remove_layer(self):
        """
        Removes both the local and web layers.
        """
        if not self._overlay_layer is None:
            QgsProject.instance().layerTreeRoot().removeLayer(self._overlay_layer)

            #Clear web overlays
            self._web_spatial_loader.removeOverlay()

            self._overlay_layer = None

    def _on_overlay_to_be_removed(self, layers_ids):
        """
        Resets the local layer variable and removes the web overlay.
        """
        if not self._overlay_layer is None:
            if self._overlay_layer.id() in layers_ids:
                self.remove_layer()

    def on_spatial_browser_error(self, err):
        """
        Slot raised when an error occurs when loading items in the property browser
        """
        self._insert_notification(err, ERROR)

    def on_spatial_browser_loading(self, progress):
        """
        Slot raised when the property browser is loading.
        Displays the progress of the page loading as a percentage.
        """
        if progress <= 0 or progress >= 100:
            self.lblInfo.setText("")
            self.lblInfo.setVisible(False)

        else:
            self.lblInfo.setVisible(True)
            self.lblInfo.setText("Loading...%d%%)"%(progress))

    def on_spatial_browser_finished(self, status):
        """
        Slot raised when the property browser finishes loading the content
        """
        if status:
            if len(self.local_map.canvas_layers()) > 0:# and not self._ol_loaded:
                self.on_sync_extents()

            self._ol_loaded = True
            #self._overlay_spatial_unit()

        else:
            msg = QApplication.translate("SpatialPreview",
                                         "Error: Spatial unit cannot be loaded.")
            self._insert_notification(msg, ERROR)

    def on_zoom_changed(self):
        """
        Slot raised when the zoom value in the slider changes.
        This is only raised once the user releases the slider with the mouse.
        """
        zoom = self.zoomSlider.value()
        self._web_spatial_loader.zoom_to_level(zoom)

    def on_load_GMaps(self, state):
        """
        Slot raised when a user clicks to set Google Maps Satellite
        as the base layer
        """
        if state:
            self._web_spatial_loader.setBaseLayer(GMAP_SATELLITE)

    def on_load_OSM(self, state):
        """
        Slot raised when a user clicks to set OSM as the base layer
        """
        if state:
            self._web_spatial_loader.setBaseLayer(OSM)

    def on_map_zoom_level_changed(self, level):
        """
        Slot which is raised when the zoom level of the map changes.
        """
        self.zoomSlider.setValue(level)

    def on_reset_web_map(self):
        """
        Slot raised when the user clicks to reset the property
        location in the map.
        """
        self._web_spatial_loader.zoom_to_extents()

    def on_sync_extents(self):
        """
        Slot raised to synchronize the webview extents with those of the
        local map canvas.
        """
        if len(self.local_map.canvas_layers()) > 0:# and self._ol_loaded:
            curr_extent = self.map_extents()
            self._web_spatial_loader.zoom_to_map_extents(curr_extent)

    def map_extents(self):
        """
        :returns: Current extents of the local map.
        :rtype: QgsRectangle
        """
        return self.local_map.extent()

    def canvas_zoom_to_extent(self, extent):
        self.local_map.canvas.setExtent(extent)
Exemplo n.º 39
0
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)
 def getFlash():
     h = QgsHighlight( self.canvas, geometry, layer )
     h.setColor(     QColor( 255, 0, 0, 255 ) )
     h.setFillColor( QColor( 255, 0, 0, 100 ) )
     h.setWidth( 2 )
     return h
Exemplo n.º 41
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
Exemplo n.º 42
0
class Start:
    def __init__(self, iface):
        self.name = "OPEN_FTTH"
        self.iface = iface
        self.autosave_enabled = False
        self.route_segment_layer = None
        self.route_node_layer = None
        self.websocket = BridgeWebsocket(self.iface)

        self.identifyHighlight = None
        self.last_identified_feature_mrid = None
        self.last_identified_feature_type = None

        self.event_handler = EventHandler(self.iface, self.websocket.websocket,
                                          self)
        self.websocket.messageReceived.connect(self.event_handler.handle)

        self.identifyNetworkElementHandler = IdentifyNetworkElementHandler(
            self.websocket)
        self.retrieve_selected_handler = RetrieveSelectedHandler(
            self.iface, self.websocket)
        self.application_settings = ApplicationSettings()
        self.layers_loaded = False

    def initGui(self):
        self.setupActions()
        self.iface.layerTreeView().currentLayerChanged.connect(
            self.layersLoaded)
        self.iface.layerTreeView().currentLayerChanged.connect(
            self.layerSelectionChange)

    def setupActions(self):
        self.actions = []

        icon_auto_save = ":/plugins/open_ftth/auto_save.svg"
        self.autosave_action = QAction(QtGui.QIcon(icon_auto_save), "Autosave",
                                       self.iface.mainWindow())
        self.autosave_action.setCheckable(True)
        self.autosave_action.triggered.connect(self.setupAutoSave)

        auto_identify = ":/plugins/open_ftth/auto_identify.svg"
        self.select_action = QAction(QtGui.QIcon(auto_identify), "Select",
                                     self.iface.mainWindow())
        self.select_action.setCheckable(True)
        self.select_action.triggered.connect(self.setupSelectTool)

        web_browser = ":/plugins/open_ftth/browser_icon.svg"
        self.web_browser_action = QAction(QtGui.QIcon(web_browser),
                                          "Web-browser",
                                          self.iface.mainWindow())
        self.web_browser_action.setCheckable(False)
        self.web_browser_action.triggered.connect(self.connectWebBrowser)

        paste_geometry = ":/plugins/open_ftth/paste_geometry.svg"
        self.paste_geometry_action = QAction(QtGui.QIcon(paste_geometry),
                                             "Paste geometry",
                                             self.iface.mainWindow())
        self.paste_geometry_action.setCheckable(False)
        self.paste_geometry_action.triggered.connect(self.pasteGeometry)

        self.iface.addPluginToMenu("&OPEN FTTH", self.select_action)
        self.iface.addToolBarIcon(self.autosave_action)
        self.iface.addToolBarIcon(self.select_action)
        self.iface.addToolBarIcon(self.web_browser_action)
        self.iface.addToolBarIcon(self.paste_geometry_action)

        self.identify_tool = IdentifySelect(self.iface.mapCanvas())
        self.identify_tool.identified.connect(self.onIdentified)
        self.identify_tool.identifiedNone.connect(self.onIdentifiedNone)
        self.buildActionListIdentifyTool()

    def buildActionListIdentifyTool(self):
        actionList = self.iface.mapNavToolToolBar().actions()

        # Add actions from QGIS attributes toolbar (handling QWidgetActions)
        tmpActionList = self.iface.attributesToolBar().actions()
        for action in tmpActionList:
            if isinstance(action, QWidgetAction):
                actionList.extend(action.defaultWidget().actions())
            else:
                actionList.append(action)

        tmpActionList = self.iface.digitizeToolBar().actions()
        for action in tmpActionList:
            if isinstance(action, QWidgetAction):
                actionList.extend(action.defaultWidget().actions())
            else:
                actionList.append(action)

        tmpActionList = self.iface.selectionToolBar().actions()
        for action in tmpActionList:
            if isinstance(action, QWidgetAction):
                actionList.extend(action.defaultWidget().actions())
            else:
                actionList.append(action)

        # Build a group with actions from actionList and add your own action
        group = QActionGroup(self.iface.mainWindow())
        group.setExclusive(True)
        for action in actionList:
            group.addAction(action)
        group.addAction(self.select_action)

    def unload(self):
        for action in self.actions:
            self.iface.removeToolBarIcon(action)

        self.autosave_action.setChecked(False)
        self.select_action.setChecked(False)

        self.autosave_enabled = False
        self.select_tool_enabled = False

        try:
            self.disconnectSelectedFeatures()
            self.disconnectSelectTool()
            self.websocket.close()
            self.route_segment_layer.beforeCommitChanges.disconnect(
                self.preCommitDeleteHandlerRouteSegment)
            self.route_node_layer.beforeCommitChanges.disconnect(
                self.preCommitDeleteHandlerRouteNode)
            self.route_node_layer.featuresDeleted.disconnect(
                self.checkFeaturesDeleted)
            self.route_segment_layer.featuresDeleted.disconnect(
                self.checkFeaturesDeleted)
        except Exception:
            pass

    def setupSelectTool(self):
        self.iface.mapCanvas().setMapTool(self.identify_tool)

    def sendSelectedFeatures(self):
        self.getSelectedFeaturesHandler.handle()

    def setupAutoSave(self):
        if self.autosave_enabled is False:
            self.connectAutosave()
            self.saveActiveLayerEdits()
        else:
            self.disconnectAutosave()

    def layersLoaded(self):
        if not self.hasCorrectLayers():
            self.onIdentifiedNone()
            return

        if self.layers_loaded is False:
            self.websocket.start()
            self.layers_loaded = True
            self.route_segment_layer = QgsProject.instance().mapLayersByName(
                ApplicationSettings().get_layers_route_segment_name())[0]
            self.route_node_layer = QgsProject.instance().mapLayersByName(
                ApplicationSettings().get_layers_route_node_name())[0]

            try:
                self.route_node_layer.featuresDeleted.connect(
                    self.checkFeaturesDeleted)
                self.route_segment_layer.featuresDeleted.connect(
                    self.checkFeaturesDeleted)
            except TypeError:
                pass

            try:
                self.route_segment_layer.beforeCommitChanges.connect(
                    self.preCommitDeleteHandlerRouteSegment)
                self.route_node_layer.beforeCommitChanges.connect(
                    self.preCommitDeleteHandlerRouteNode)
            except TypeError:
                pass

    def layerSelectionChange(self):
        if not self.hasCorrectLayers():
            self.onIdentifiedNone()
            return

        self.route_segment_layer = QgsProject.instance().mapLayersByName(
            ApplicationSettings().get_layers_route_segment_name())[0]
        try:
            self.route_segment_layer.selectionChanged.disconnect(
                self.onSelectedSegment)
        except TypeError:
            pass

        self.route_segment_layer.selectionChanged.connect(
            self.onSelectedSegment)

    def hasCorrectLayers(self):
        route_segment_layers = QgsProject.instance().mapLayersByName(
            ApplicationSettings().get_layers_route_segment_name())
        route_node_layers = QgsProject.instance().mapLayersByName(
            ApplicationSettings().get_layers_route_node_name())
        return len(route_segment_layers) > 0 and len(route_node_layers) > 0

    def connectAutosave(self):
        # We do this to avoid plugin crash in case that connects come in an invalid state.
        try:
            self.route_segment_layer = QgsProject.instance().mapLayersByName(
                ApplicationSettings().get_layers_route_segment_name())[0]
            self.route_segment_layer.layerModified.connect(
                self.saveActiveLayerEdits)
        except TypeError:
            pass

        # We do this to avoid plugin crash in case that connects come in an invalid state.
        try:
            self.route_node_layer = QgsProject.instance().mapLayersByName(
                ApplicationSettings().get_layers_route_node_name())[0]
            self.route_node_layer.layerModified.connect(
                self.saveActiveLayerEdits)
        except TypeError:
            pass

        self.autosave_enabled = True

    def disconnectAutosave(self):
        # We do this to avoid plugin crash in case that connects come in an invalid state.
        try:
            self.route_segment_layer.layerModified.disconnect(
                self.saveActiveLayerEdits)
        except TypeError:
            pass

        # We do this to avoid plugin crash in case that connects come in an invalid state.
        try:
            self.route_node_layer.layerModified.disconnect(
                self.saveActiveLayerEdits)
        except TypeError:
            pass

        self.autosave_action.setChecked(False)
        self.autosave_enabled = False

    def connectWebBrowser(self):
        webbrowser.open(self.application_settings.get_website_url(), new=2)

    def saveActiveLayerEdits(self):
        self.iface.actionSaveActiveLayerEdits().trigger()

    def onSelectedSegment(self):
        message = type(
            'Expando', (object, ),
            {'username': self.application_settings.get_user_name_prefix()})()
        self.retrieve_selected_handler.handle(message)

    def checkFeaturesDeleted(self, fids):
        if self.last_identified_feature_mrid is None:
            return

        features = None
        filterExpression = f'"mrid" = \'{self.last_identified_feature_mrid}\''
        if self.last_identified_feature_type == self.application_settings.get_types_route_node(
        ):
            features = self.route_node_layer.getFeatures(
                QgsFeatureRequest().setFilterExpression(filterExpression))
        elif self.last_identified_feature_type == self.application_settings.get_types_route_segment(
        ):
            features = self.route_segment_layer.getFeatures(
                QgsFeatureRequest().setFilterExpression(filterExpression))
        else:
            return

        # hack because the deleted signal is triggered on both create and delete
        stillExists = False
        for feature in features:
            stillExists = True

        if not stillExists:
            self.onIdentifiedNone()
            self.identifyNetworkElementHandler.handle(None, None)
        # end of hack

    def onIdentified(self, selected_layer, selected_feature):
        selected_type = ""
        if self.application_settings.get_layers_route_node_name(
        ) == selected_layer.sourceName():
            selected_type = self.application_settings.get_types_route_node()
        elif self.application_settings.get_layers_route_segment_name(
        ) == selected_layer.sourceName():
            selected_type = self.application_settings.get_types_route_segment()
        else:
            self.identifyHighlight.hide()
            return

        if self.identifyHighlight is not None:
            self.identifyHighlight.hide()

        color = QColor(0, 255, 0)
        self.identifyHighlight = QgsHighlight(self.iface.mapCanvas(),
                                              selected_feature.geometry(),
                                              selected_layer)
        self.identifyHighlight.setWidth(3)
        self.identifyHighlight.setColor(color)
        self.identifyHighlight.show()

        mrid = selected_feature.attribute("mrid")

        self.last_identified_feature_mrid = mrid
        self.last_identified_feature_type = selected_type

        if selected_type != "":
            self.identifyNetworkElementHandler.handle(mrid, selected_type)

    def onIdentifiedNone(self):
        if self.identifyHighlight is not None:
            self.last_identified_feature_mrid = None
            self.last_identified_feature_type = None
            self.identifyHighlight.hide()

    def preCommitDeleteHandlerRouteSegment(self):
        self.undoDeleteSetMarkedToBeDeleted(
            ApplicationSettings().get_layers_route_segment_name())

    def preCommitDeleteHandlerRouteNode(self):
        self.undoDeleteSetMarkedToBeDeleted(
            ApplicationSettings().get_layers_route_node_name())

    def undoDeleteSetMarkedToBeDeleted(self, layerName):
        layers = QgsProject.instance().mapLayersByName(layerName)
        if len(layers) != 1:
            return
        layer = layers[0]

        deleted_features_ids = layer.editBuffer().deletedFeatureIds()
        for feature_id in deleted_features_ids:
            QgsVectorLayerUndoCommandDeleteFeature(layer.editBuffer(),
                                                   feature_id).undo()

        marked_to_be_deleted_idx = layer.fields().indexOf(
            'marked_to_be_deleted')
        user_name_idx = layer.fields().indexOf('user_name')
        user_name = self.application_settings.get_user_name()
        for feature in layer.dataProvider().getFeatures(
                QgsFeatureRequest().setFilterFids(deleted_features_ids)):
            layer.changeAttributeValue(feature.id(), marked_to_be_deleted_idx,
                                       True)
            layer.changeAttributeValue(feature.id(), user_name_idx, user_name)

    def pasteGeometry(self):
        layer = self.iface.activeLayer()

        route_segment_layer_name = self.application_settings.get_layers_route_segment_name(
        )
        if layer.sourceName() != route_segment_layer_name:
            self.showBarMessage(
                "You can only paste a geometry when layer %s is selected." %
                route_segment_layer_name, Qgis.Warning)
            return

        if not layer.isEditable():
            self.showBarMessage(
                "You need to be in edit mode to paste the geometry.",
                Qgis.Warning)
            return

        geoms = self.tryGetFeaturesGeomsFromClipBoard()
        if len(geoms) > 1:
            self.showBarMessage(
                "Can't paste geometry multiple features in clipboard.",
                Qgis.Warning)
            return

        if len(geoms) == 0:
            self.showBarMessage(
                "Can't paste geometry. No features in clipboard.",
                Qgis.Warning)
            return

        selected_features_iter = layer.getSelectedFeatures()
        selected_features = []
        for selected_feature in selected_features_iter:
            selected_features.append(selected_feature)

        if len(selected_features) == 0:
            self.showBarMessage("Can't paste. No target feature to paste to.",
                                Qgis.Warning)
            return

        # Paste is the comment we want to paste to
        paste_feature = selected_features[0]
        paste_geom = paste_feature.geometry()

        # Copy is the geom from the clipboard that we want "paste" to resemble.
        copy_geom = geoms[0]

        if paste_geom.type() != copy_geom.type():
            self.showBarMessage(
                "Not the same geometry type. From %s to %s" %
                (copy_geom.type(), paste_geom.type()), Qgis.Warning)
            return

        paste_geom_start = paste_geom.asPolyline()[0]
        paste_geom_end = paste_geom.asPolyline()[len(paste_geom.asPolyline()) -
                                                 1]
        copy_geom_start = copy_geom.asPolyline()[0]
        copy_geom_end = copy_geom.asPolyline()[len(copy_geom.asPolyline()) - 1]

        start_to_start_distance = paste_geom_start.distance(copy_geom_start)
        start_to_end_distance = paste_geom_start.distance(copy_geom_end)

        new_copy_polyline = copy_geom.asPolyline()

        if start_to_start_distance > start_to_end_distance:
            QgsMessageLog.logMessage(
                "The geometries are flipped, we reverse them for the copy.",
                self.name, Qgis.Info)
            new_copy_polyline.reverse()

        # Its important that we do this after, in case that the geometry is reversed.
        new_copy_geom_start = new_copy_polyline[0]
        new_copy_geom_end = new_copy_polyline[len(new_copy_polyline) - 1]

        new_start_to_start_distance = paste_geom_start.distance(
            new_copy_geom_start)
        if self.application_settings.get_tolerance(
        ) < new_start_to_start_distance:
            self.showBarMessage(
                "Start point distance is bigger than tolerance.",
                Qgis.Critical)
            return

        new_start_to_end_distance = paste_geom_end.distance(new_copy_geom_end)
        if self.application_settings.get_tolerance(
        ) < new_start_to_end_distance:
            self.showBarMessage(
                "End points distance is bigger than tolerance.", Qgis.Critical)
            return

        # We update the geometry.
        result = layer.changeGeometry(
            paste_feature.id(), QgsGeometry.fromPolylineXY(new_copy_polyline))

        # We change the mapping method to LandSurveying to identify that the polyline now matches the landsurvey polyline.
        mapping_method_idx = layer.fields().indexOf('mapping_method')
        layer.changeAttributeValue(paste_feature.id(), mapping_method_idx,
                                   "LandSurveying")

        if not result:
            self.showBarMessage("Can't paste geometry, something went wrong.",
                                Qgis.Critical)
            return

        self.iface.mapCanvas().refresh()

    def tryGetFeaturesGeomsFromClipBoard(self):
        cb = QApplication.clipboard()
        clipboard_text = cb.text()
        if sys.version_info[0] == 2:
            clipboard_text = clipboard_text.encode('utf-8')

        reader = csv.DictReader(StringIO(clipboard_text), delimiter='\t')

        geoms = []
        for row in reader:
            wkt_geom = row.get('wkt_geom')
            geom = QgsGeometry.fromWkt(wkt_geom)

            if not geom:
                self.showBarMessage(
                    'Can\'t create geometry from wkt: %s' % wkt_geom,
                    Qgis.Critical)
                return []

            geoms.append(geom)
        return geoms

    def showBarMessage(self, message, level=Qgis.Info, duration=-1):
        self.iface.messageBar().pushMessage("Error",
                                            message,
                                            level=level,
                                            duration=duration)