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 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)
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 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 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 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()
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 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
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)
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()
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)
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)
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)
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)
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()
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()
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)
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)
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))
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 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()
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)
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()
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
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
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()
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)
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)
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)
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)
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
class LinkerDock(QDockWidget, Ui_linker, SettingDialog): def __init__(self, iface): # QGIS self.iface = iface self.settings = MySettings() self.linkRubber = QgsRubberBand(self.iface.mapCanvas()) self.featureHighlight = None # Relation management self.relationManager = QgsProject.instance().relationManager() self.relationManager.changed.connect(self.loadRelations) self.relation = QgsRelation() self.referencingFeature = QgsFeature() self.relationWidgetWrapper = None self.editorContext = QgsAttributeEditorContext() self.editorContext.setVectorLayerTools(self.iface.vectorLayerTools()) # GUI QDockWidget.__init__(self) self.setupUi(self) SettingDialog.__init__(self, MySettings(), False, True) self.drawButton.setChecked(self.settings.value("drawEnabled")) self.relationReferenceWidget.setAllowMapIdentification(True) self.relationReferenceWidget.setEmbedForm(False) self.mapTool = QgsMapToolIdentifyFeature(self.iface.mapCanvas()) self.mapTool.setButton(self.identifyReferencingFeatureButton) # Connect signal/slot self.relationComboBox.currentIndexChanged.connect(self.currentRelationChanged) self.mapTool.featureIdentified.connect(self.setReferencingFeature) # load relations at start self.loadRelations() def showEvent(self, QShowEvent): self.drawLink() def closeEvent(self, e): self.iface.mapCanvas().unsetMapTool(self.mapTool) self.linkRubber.reset() self.deleteHighlight() self.deleteWrapper() self.disconnectLayer() def disconnectLayer(self): if self.relation.isValid(): self.relation.referencingLayer().editingStarted.disconnect(self.relationEditableChanged) self.relation.referencingLayer().editingStopped.disconnect(self.relationEditableChanged) self.relation.referencingLayer().attributeValueChanged.disconnect(self.layerValueChangedOutside) def runForFeature(self, relationId, layer, feature): index = self.relationComboBox.findData(relationId) self.relationComboBox.setCurrentIndex(index) self.setReferencingFeature(feature) self.show() if not layer.isEditable(): self.iface.messageBar().pushMessage("Link It", "Cannot set a new related feature since %s is not editable" % layer.name(), QgsMessageBar.WARNING, 4) else: self.relationReferenceWidget.mapIdentification() @pyqtSlot(name="on_identifyReferencingFeatureButton_clicked") def activateMapTool(self): self.iface.mapCanvas().setMapTool(self.mapTool) def deactivateMapTool(self): self.iface.mapCanvas().unsetMapTool(self.mapTool) def loadRelations(self): self.deleteWrapper() self.disconnectLayer() self.relation = QgsRelation() self.referencingFeature = QgsFeature() self.relationComboBox.currentIndexChanged.disconnect(self.currentRelationChanged) self.relationComboBox.clear() for relation in self.relationManager.referencedRelations(): if relation.referencingLayer().hasGeometryType(): self.relationComboBox.addItem(relation.name(), relation.id()) self.relationComboBox.setCurrentIndex(-1) self.relationComboBox.currentIndexChanged.connect(self.currentRelationChanged) self.currentRelationChanged(-1) def currentRelationChanged(self, index): # disconnect previous relation if self.relation.isValid(): try: self.relation.referencingLayer().editingStarted.disconnect(self.relationEditableChanged) self.relation.referencingLayer().editingStopped.disconnect(self.relationEditableChanged) self.relation.referencingLayer().attributeValueChanged.disconnect(self.layerValueChangedOutside) except TypeError: pass self.referencingFeatureLayout.setEnabled(index >= 0) relationId = self.relationComboBox.itemData(index) self.relation = self.relationManager.relation(relationId) self.mapTool.setLayer(self.relation.referencingLayer()) self.setReferencingFeature() # connect if self.relation.isValid(): self.relation.referencingLayer().editingStarted.connect(self.relationEditableChanged) self.relation.referencingLayer().editingStopped.connect(self.relationEditableChanged) self.relation.referencingLayer().attributeValueChanged.connect(self.layerValueChangedOutside) def setReferencingFeature(self, feature=QgsFeature()): self.deactivateMapTool() self.referencingFeature = QgsFeature(feature) self.deleteWrapper() # disable relation reference widget if no referencing feature self.referencedFeatureLayout.setEnabled(feature.isValid()) # set line edit if not self.relation.isValid() or not feature.isValid(): self.referencingFeatureLineEdit.clear() return self.referencingFeatureLineEdit.setText("%s" % feature.id()) fieldIdx = self.referencingFieldIndex() widgetConfig = self.relation.referencingLayer().editorWidgetV2Config(fieldIdx) self.relationWidgetWrapper = QgsEditorWidgetRegistry.instance().create("RelationReference", self.relation.referencingLayer(), fieldIdx, widgetConfig, self.relationReferenceWidget, self, self.editorContext) self.relationWidgetWrapper.setEnabled(self.relation.referencingLayer().isEditable()) self.relationWidgetWrapper.setValue(feature[fieldIdx]) self.relationWidgetWrapper.valueChanged.connect(self.foreignKeyChanged) # override field definition to allow map identification self.relationReferenceWidget.setAllowMapIdentification(True) self.relationReferenceWidget.setEmbedForm(False) # update drawn link self.highlightReferencingFeature() self.drawLink() def deleteWrapper(self): if self.relationWidgetWrapper is not None: self.relationWidgetWrapper.valueChanged.disconnect(self.foreignKeyChanged) self.relationWidgetWrapper.setValue(None) del self.relationWidgetWrapper self.relationWidgetWrapper = None def foreignKeyChanged(self, newKey): if not self.relation.isValid() or not self.relation.referencingLayer().isEditable() or not self.referencingFeature.isValid(): self.drawLink() return if not self.relation.referencingLayer().editBuffer().changeAttributeValue(self.referencingFeature.id(), self.referencingFieldIndex(), newKey): self.iface.messageBar().pushMessage("Link It", "Cannot change attribute value.", QgsMessageBar.CRITICAL) self.drawLink() def relationEditableChanged(self): if self.relationWidgetWrapper is not None: self.relationWidgetWrapper.setEnabled(self.relation.isValid() and self.relation.referencingLayer().isEditable()) def layerValueChangedOutside(self, fid, fieldIdx, value): if not self.relation.isValid() or not self.referencingFeature.isValid() or self.relationWidgetWrapper is None: return # not the correct feature if fid != self.referencingFeature.id(): return # not the correct field if fieldIdx != self.referencingFieldIndex(): return # widget already has this value if value == self.relationWidgetWrapper.value(): return self.relationWidgetWrapper.valueChanged.disconnect(self.foreignKeyChanged) self.relationWidgetWrapper.setValue(value) self.relationWidgetWrapper.valueChanged.connect(self.foreignKeyChanged) def referencingFieldIndex(self): if not self.relation.isValid(): return -1 fieldName = self.relation.fieldPairs().keys()[0] fieldIdx = self.relation.referencingLayer().fieldNameIndex(fieldName) return fieldIdx @pyqtSlot(bool, name="on_drawButton_toggled") def drawLink(self): self.settings.setValue("drawEnabled", self.drawButton.isChecked()) self.linkRubber.reset() if not self.drawButton.isChecked() or not self.referencingFeature.isValid() or not self.relation.isValid(): return referencedFeature = self.relationReferenceWidget.referencedFeature() if not referencedFeature.isValid(): return p1 = self.centroid(self.relation.referencedLayer(), referencedFeature) p2 = self.centroid(self.relation.referencingLayer(), self.referencingFeature) geom = arc(p1, p2) self.linkRubber.setToGeometry(geom, None) self.linkRubber.setWidth(self.settings.value("rubberWidth")) self.linkRubber.setColor(self.settings.value("rubberColor")) self.linkRubber.setLineStyle(Qt.DashLine) def centroid(self, layer, feature): geom = feature.geometry() if geom.type() == QGis.Line: geom = geom.interpolate(geom.length()/2) else: geom = geom.centroid() return self.iface.mapCanvas().mapSettings().layerToMapCoordinates(layer, geom.asPoint()) @pyqtSlot(name="on_highlightReferencingFeatureButton_clicked") def highlightReferencingFeature(self): self.deleteHighlight() if not self.relation.isValid() or not self.referencingFeature.isValid(): return self.featureHighlight = QgsHighlight(self.iface.mapCanvas(), self.referencingFeature.geometry(), self.relation.referencingLayer()) settings = QSettings() color = QColor( settings.value("/Map/highlight/color", QGis.DEFAULT_HIGHLIGHT_COLOR.name())) alpha = int(settings.value("/Map/highlight/colorAlpha", QGis.DEFAULT_HIGHLIGHT_COLOR.alpha())) bbuffer = float(settings.value("/Map/highlight/buffer", QGis.DEFAULT_HIGHLIGHT_BUFFER_MM)) minWidth = float(settings.value("/Map/highlight/minWidth", QGis.DEFAULT_HIGHLIGHT_MIN_WIDTH_MM)) self.featureHighlight.setColor(color) color.setAlpha(alpha) self.featureHighlight.setFillColor(color) self.featureHighlight.setBuffer(bbuffer) self.featureHighlight.setMinWidth(minWidth) self.featureHighlight.show() timer = QTimer(self) timer.setSingleShot(True) timer.timeout.connect(self.deleteHighlight) timer.start(3000) def deleteHighlight(self): if self.featureHighlight: del self.featureHighlight self.featureHighlight = None
class 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)