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
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 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)
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 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 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)
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