From 20387578d603eabe82e88983a164a7533121b6ce Mon Sep 17 00:00:00 2001 From: Tim Sutton Date: Sun, 1 Dec 2024 20:33:28 +0000 Subject: [PATCH 1/3] Updates to layer status calcs and show error button on attributes --- geest/core/json_tree_item.py | 13 ++++-- geest/gui/panels/tree_panel.py | 27 +++++++++++- .../vector_and_field_datasource_widget.py | 3 +- geest/utilities.py | 41 ++++++++++++++++++- shell.nix | 2 +- 5 files changed, 78 insertions(+), 8 deletions(-) diff --git a/geest/core/json_tree_item.py b/geest/core/json_tree_item.py index 7eaa865c..495b3a52 100644 --- a/geest/core/json_tree_item.py +++ b/geest/core/json_tree_item.py @@ -237,7 +237,8 @@ def getStatus(self): qgis_layer_source_key = analysis_mode.replace("use_", "") + "_layer_source" qgis_layer_shapefile_key = analysis_mode.replace("use_", "") + "_shapefile" status = "" - + if "Workflow Completed" in data.get("result", ""): + return "Completed successfully" # First check if the item weighting is 0, or its parent factor is zero # If so, return "Excluded from analysis" if self.isIndicator(): @@ -269,10 +270,17 @@ def getStatus(self): return "Excluded from analysis" # If the sum of the indicator weightings is zero, return "Excluded from analysis" weight_sum = 0 + unconfigured_child_count = 0 for child in self.childItems: weight_sum += float(child.attribute("factor_weighting", 0.0)) + if child.getStatus() == "Not configured (optional)": + unconfigured_child_count += 1 + if child.getStatus() == "Required and not configured": + unconfigured_child_count += 1 if not weight_sum: return "Excluded from analysis" + if unconfigured_child_count: + return "Required and not configured" # # Note we avoid infinite recursion by NOT doing the checks below using the getStatus # method of the parent. @@ -339,8 +347,7 @@ def getStatus(self): "result_file", "" ): return "Workflow failed" - if "Workflow Completed" in data.get("result", ""): - return "Completed successfully" + return "WRITE TOOL TIP" except Exception as e: diff --git a/geest/gui/panels/tree_panel.py b/geest/gui/panels/tree_panel.py index d496554b..0abb99e0 100644 --- a/geest/gui/panels/tree_panel.py +++ b/geest/gui/panels/tree_panel.py @@ -620,7 +620,8 @@ def show_attributes(self, item): table.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Stretch ) # Only the second column stretches - + # Track if "error_file" exists + error_file_content = None # Populate the table with the sorted data for row, (key, value) in enumerate(sorted_data.items()): key_item = QTableWidgetItem(key) @@ -637,6 +638,15 @@ def show_attributes(self, item): value_item = QTableWidgetItem(str(value)) value_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) table.setItem(row, 1, value_item) + # Check if this row contains "error_file" + if key == "error_file" and isinstance(value, str): + try: + with open(value, "r") as file: + error_file_content = file.read() + except (OSError, IOError): + error_file_content = f"Unable to read file: {value}" + except Exception as e: + error_file_content = f"Error reading file: {e}" layout.addWidget(table) @@ -658,6 +668,13 @@ def show_attributes(self, item): copy_button.clicked.connect(lambda: self.copy_to_clipboard_as_markdown(table)) button_layout.addWidget(copy_button) + # Show Error File button + if error_file_content is not None: + show_error_file_button = QPushButton("Show Error File") + button_layout.addWidget(show_error_file_button) + show_error_file_button.clicked.connect( + lambda: self.show_error_file_popup(error_file_content) + ) layout.addLayout(button_layout) # Enable custom context menu for the table @@ -668,7 +685,13 @@ def show_attributes(self, item): dialog.exec_() - log_message("----------------------------") + def show_error_file_popup(self, error_file_content): + """Show a popup message with the contents of the error file.""" + msg_box = QMessageBox() + msg_box.setWindowTitle("Error File Contents") + msg_box.setText(error_file_content) + msg_box.setStandardButtons(QMessageBox.Ok) + msg_box.exec_() def copy_to_clipboard_as_markdown(self, table: QTableWidget): """Copy the table content as Markdown to the clipboard.""" diff --git a/geest/gui/widgets/datasource_widgets/vector_and_field_datasource_widget.py b/geest/gui/widgets/datasource_widgets/vector_and_field_datasource_widget.py index 04094119..3828872e 100644 --- a/geest/gui/widgets/datasource_widgets/vector_and_field_datasource_widget.py +++ b/geest/gui/widgets/datasource_widgets/vector_and_field_datasource_widget.py @@ -15,7 +15,7 @@ ) from qgis.gui import QgsFieldComboBox from qgis.PyQt.QtCore import QSettings -from geest.utilities import log_message +from geest.utilities import log_message, geest_layer_ids from .base_datasource_widget import BaseDataSourceWidget @@ -42,6 +42,7 @@ def add_internal_widgets(self) -> None: filter = QgsMapLayerProxyModel.PolygonLayer else: filter = QgsMapLayerProxyModel.PointLayer + self.layer_combo = QgsMapLayerComboBox() self.layer_combo.setFilters(filter) self.layer_combo.setAllowEmptyLayer(True) diff --git a/geest/utilities.py b/geest/utilities.py index b0c84563..83c0c2f0 100644 --- a/geest/utilities.py +++ b/geest/utilities.py @@ -23,7 +23,7 @@ import inspect from qgis.PyQt.QtCore import QUrl from qgis.PyQt import uic -from qgis.core import QgsMessageLog, Qgis +from qgis.core import QgsMessageLog, Qgis, QgsProject from geest.core import setting @@ -117,3 +117,42 @@ def log_message( logging.critical(full_message) else: logging.debug(full_message) + + +def geest_layer_ids(): + """Get a list of the layer ids in the Geest group. + + This is useful for filtering layers in the layer combo boxes. + + e.g.: + + layer_ids = geest_layer_ids() + def custom_filter(layer): + return layer.id() not in layer_ids + map_layer_combo.setFilters(QgsMapLayerProxyModel.CustomLayerFilter) + map_layer_combo.proxyModel().setCustomFilterFunction(custom_filter) + + """ + # Get the layer tree root + root = QgsProject.instance().layerTreeRoot() + + # Find the "Geest" group + geest_group = root.findGroup("Geest") + if not geest_group: + # No group named "Geest," no need to filter + return + + # Recursively collect IDs of all layers in the "Geest" group + def collect_layer_ids(group: QgsLayerTreeGroup) -> set: + layer_ids = set() + for child in group.children(): + if isinstance(child, QgsLayerTreeGroup): + # Recursively collect from subgroups + layer_ids.update(collect_layer_ids(child)) + elif hasattr(child, "layerId"): # Check if the child is a layer + layer_ids.add(child.layerId()) + return layer_ids + + geest_layer_ids = collect_layer_ids(geest_group) + + return geest_layer_ids diff --git a/shell.nix b/shell.nix index 228da379..d2276e87 100644 --- a/shell.nix +++ b/shell.nix @@ -1,7 +1,7 @@ with import { }; let # For packages pinned to a specific version - pinnedHash = "nixos-24.05"; + pinnedHash = "nixos-24.11"; pinnedPkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/${pinnedHash}.tar.gz") { }; pythonPackages = python3Packages; in pkgs.mkShell rec { From 5f1bc0aabb7cbd0313b71e5c917f7ddbadb528c4 Mon Sep 17 00:00:00 2001 From: Tim Sutton Date: Sun, 1 Dec 2024 20:33:53 +0000 Subject: [PATCH 2/3] Updates to layer status calcs and show error button on attributes --- .../datasource_widgets/vector_and_field_datasource_widget.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geest/gui/widgets/datasource_widgets/vector_and_field_datasource_widget.py b/geest/gui/widgets/datasource_widgets/vector_and_field_datasource_widget.py index 3828872e..4a4b100b 100644 --- a/geest/gui/widgets/datasource_widgets/vector_and_field_datasource_widget.py +++ b/geest/gui/widgets/datasource_widgets/vector_and_field_datasource_widget.py @@ -15,7 +15,7 @@ ) from qgis.gui import QgsFieldComboBox from qgis.PyQt.QtCore import QSettings -from geest.utilities import log_message, geest_layer_ids +from geest.utilities import log_message from .base_datasource_widget import BaseDataSourceWidget From e633c76e0d7ee33712c213ce739ce42df8c2b02a Mon Sep 17 00:00:00 2001 From: Tim Sutton Date: Sun, 1 Dec 2024 23:27:24 +0000 Subject: [PATCH 3/3] Fix for #620 and use consistent layer references --- geest/core/json_tree_item.py | 18 +++++++++++- .../raster_reclassification_workflow.py | 10 +++---- .../core/workflows/safety_raster_workflow.py | 8 ++--- geest/gui/datasource_widget_factory.py | 12 ++++---- geest/gui/indicator_configuration_widget.py | 14 +++++---- .../acled_csv_layer_widget.py | 2 +- .../multi_buffer_distances_widget.py | 26 ++++++++--------- .../raster_reclassification_widget.py | 3 +- .../combined_widgets/safety_raster_widget.py | 3 +- .../single_buffer_distance_widget.py | 29 ++++++++++--------- .../raster_datasource_widget.py | 1 + 11 files changed, 75 insertions(+), 51 deletions(-) diff --git a/geest/core/json_tree_item.py b/geest/core/json_tree_item.py index 495b3a52..057139dd 100644 --- a/geest/core/json_tree_item.py +++ b/geest/core/json_tree_item.py @@ -236,6 +236,7 @@ def getStatus(self): analysis_mode = data.get("analysis_mode", "") qgis_layer_source_key = analysis_mode.replace("use_", "") + "_layer_source" qgis_layer_shapefile_key = analysis_mode.replace("use_", "") + "_shapefile" + qgis_layer_raster_key = analysis_mode.replace("use_", "") + "_raster" status = "" if "Workflow Completed" in data.get("result", ""): return "Completed successfully" @@ -331,12 +332,27 @@ def getStatus(self): ): return "Not configured (optional)" if ( + # Test for algs requiring vector inputs self.isIndicator() - and analysis_mode != "use_default_index_score" + and analysis_mode + not in ["use_default_index_score", "use_environmental_hazards"] and not data.get(qgis_layer_source_key, False) and not data.get(qgis_layer_shapefile_key, False) ): return "Not configured (optional)" + if ( + # Test for algs requiring raster inputs + self.isIndicator() + and analysis_mode not in ["use_default_index_score"] + and analysis_mode in ["use_environmental_hazards"] + and not data.get(qgis_layer_source_key, False) + and not data.get(qgis_layer_raster_key, False) + ): + # log_message(f"Indicator {data.get('id')} is missing a raster input") + # log_message(f"analysis_mode in use_default_index_score, use_environmental_hazards: {analysis_mode in ['use_default_index_score', 'use_environmental_hazards']}") + # log_message(f"qgis_layer_source_key: {qgis_layer_source_key}: {data.get(qgis_layer_source_key, False)}") + # log_message(f"qgis_layer_raster_key: {qgis_layer_raster_key}: {data.get(qgis_layer_raster_key, False)}") + return "Not configured (optional)" if "Not Run" in data.get("result", "") and not data.get("result_file", ""): return "Configured, not run" if not data.get("result", False): diff --git a/geest/core/workflows/raster_reclassification_workflow.py b/geest/core/workflows/raster_reclassification_workflow.py index 6a53271e..9e7389ea 100644 --- a/geest/core/workflows/raster_reclassification_workflow.py +++ b/geest/core/workflows/raster_reclassification_workflow.py @@ -45,20 +45,18 @@ def __init__( else: self.range_boundaries = 0 # default value for range boundaries - layer_name = self.attributes.get("use_environmental_hazards_raster", None) + layer_name = self.attributes.get("environmental_hazards_raster", None) if not layer_name: log_message( - "Invalid layer found in use_environmental_hazards_raster, trying use_environmental_hazards_layer_source.", + "Invalid layer found in environmental_hazards_raster, trying environmental_hazards_layer_source.", tag="Geest", level=Qgis.Warning, ) - layer_name = self.attributes.get( - "use_environmental_hazards_layer_source", None - ) + layer_name = self.attributes.get("environmental_hazards_layer_source", None) if not layer_name: log_message( - "No layer found in use_environmental_hazards_layer_source.", + "No layer found in environmental_hazards_layer_source.", tag="Geest", level=Qgis.Warning, ) diff --git a/geest/core/workflows/safety_raster_workflow.py b/geest/core/workflows/safety_raster_workflow.py index 708e76e6..500e70f5 100644 --- a/geest/core/workflows/safety_raster_workflow.py +++ b/geest/core/workflows/safety_raster_workflow.py @@ -36,18 +36,18 @@ def __init__( item, cell_size_m, feedback, context ) # ⭐️ Item is a reference - whatever you change in this item will directly update the tree self.workflow_name = "use_nighttime_lights" - layer_name = self.attributes.get("use_nighttime_lights_raster", None) + layer_name = self.attributes.get("nighttime_lights_raster", None) if not layer_name: log_message( - "Invalid raster found in use_nighttime_lights_raster, trying use_nighttime_lights_layer_source.", + "Invalid raster found in nighttime_lights_raster, trying nighttime_lights_layer_source.", tag="Geest", level=Qgis.Warning, ) - layer_name = self.attributes.get("use_nighttime_lights_layer_source", None) + layer_name = self.attributes.get("nighttime_lights_layer_source", None) if not layer_name: log_message( - "No points layer found in use_nighttime_lights_layer_source.", + "No points layer found in nighttime_lights_layer_source.", tag="Geest", level=Qgis.Warning, ) diff --git a/geest/gui/datasource_widget_factory.py b/geest/gui/datasource_widget_factory.py index 48733837..7e4e797a 100644 --- a/geest/gui/datasource_widget_factory.py +++ b/geest/gui/datasource_widget_factory.py @@ -64,10 +64,12 @@ def create_widget( widget_key=cleaned_key, attributes=attributes ) if widget_key == "use_csv_point_per_cell" and value == 1: - return CsvDataSourceWidget(widget_key=widget_key, attributes=attributes) + return CsvDataSourceWidget( + cleaned_key=widget_key, attributes=attributes + ) if widget_key == "use_csv_to_point_layer" and value == 1: return AcledCsvDataSourceWidget( - widget_key=widget_key, attributes=attributes + widget_key=cleaned_key, attributes=attributes ) if widget_key == "use_classify_polygon_into_classes" and value == 1: return VectorAndFieldDataSourceWidget( @@ -79,15 +81,15 @@ def create_widget( ) if widget_key == "use_nighttime_lights" and value == 1: return RasterDataSourceWidget( - widget_key=widget_key, attributes=attributes + widget_key=cleaned_key, attributes=attributes ) if widget_key == "use_environmental_hazards" and value == 1: return RasterDataSourceWidget( - widget_key=widget_key, attributes=attributes + widget_key=cleaned_key, attributes=attributes ) if widget_key == "use_street_lights" and value == 1: return VectorDataSourceWidget( - widget_key=widget_key, attributes=attributes + widget_key=cleaned_key, attributes=attributes ) else: log_message( diff --git a/geest/gui/indicator_configuration_widget.py b/geest/gui/indicator_configuration_widget.py index 890b4810..608c2ac2 100644 --- a/geest/gui/indicator_configuration_widget.py +++ b/geest/gui/indicator_configuration_widget.py @@ -24,6 +24,9 @@ def __init__(self, attributes: dict) -> None: self.create_radio_buttons(attributes) except Exception as e: log_message(f"Error in create_radio_buttons: {e}", level=Qgis.Critical) + import traceback + + log_message(traceback.format_exc(), level=Qgis.Critical) self.setLayout(self.layout) @@ -31,12 +34,13 @@ def create_radio_buttons(self, attributes: dict) -> None: """ Uses the factory to create radio buttons from attributes dictionary. """ - # make a deep copy of the dictionary in case it changes while we - # are using it - attributes = attributes.copy() - analysis_mode = attributes.get("analysis_mode", "") - for key, value in attributes.items(): + analysis_mode = attributes.get("analysis_mode", "") + # We iterate over a list to defend against changes to the dictionary + # See issue #620. This is a workaround until we can refactor the code + # The issue is that the dictionary is being modified while we are iterating over it + # by the safety_polygon_configuration_widget.py file I think. + for key, value in list(attributes.items()): radio_button_widget = CombinedWidgetFactory.create_radio_button( key, value, attributes ) diff --git a/geest/gui/widgets/combined_widgets/acled_csv_layer_widget.py b/geest/gui/widgets/combined_widgets/acled_csv_layer_widget.py index 4ccc96cd..089d2034 100644 --- a/geest/gui/widgets/combined_widgets/acled_csv_layer_widget.py +++ b/geest/gui/widgets/combined_widgets/acled_csv_layer_widget.py @@ -34,7 +34,7 @@ def add_internal_widgets(self) -> None: """ try: self.main_layout = QVBoxLayout() - self.widget_key = "use_csv_to_point_layer" + self.widget_key = "csv_to_point_layer" # impact distance input self.buffer_distance_layout = QHBoxLayout() diff --git a/geest/gui/widgets/combined_widgets/multi_buffer_distances_widget.py b/geest/gui/widgets/combined_widgets/multi_buffer_distances_widget.py index db8f3c8a..e092f611 100644 --- a/geest/gui/widgets/combined_widgets/multi_buffer_distances_widget.py +++ b/geest/gui/widgets/combined_widgets/multi_buffer_distances_widget.py @@ -26,7 +26,7 @@ def add_internal_widgets(self) -> None: """ try: self.main_layout = QVBoxLayout() - + self.widget_key = "multi_buffer_point" # Point Layer Combobox - Filtered to point layers self.point_layer_label = QLabel( "Point Layer - shapefile will have preference" @@ -38,12 +38,12 @@ def add_internal_widgets(self) -> None: self.main_layout.addWidget(self.layer_combo) # Set the selected QgsVectorLayer in QgsMapLayerComboBox - layer_id = self.attributes.get("multi_buffer_point_layer_id", None) + layer_id = self.attributes.get(f"{self.widget_key}_layer_id", None) if layer_id: layer = QgsProject.instance().mapLayer(layer_id) if layer: self.layer_combo.setLayer(layer) - layer_id = self.attributes.get("multi_buffer_point_layer_id") + layer_id = self.attributes.get(f"{self.widget_key}_layer_id") layer = QgsProject.instance().mapLayer(layer_id) if layer and isinstance(layer, QgsVectorLayer): @@ -55,9 +55,9 @@ def add_internal_widgets(self) -> None: self.shapefile_button = QToolButton() self.shapefile_button.setText("...") self.shapefile_button.clicked.connect(self.select_shapefile) - if self.attributes.get("multi_buffer_point_shapefile", False): + if self.attributes.get(f"{self.widget_key}_shapefile", False): self.shapefile_line_edit.setText( - self.attributes["multi_buffer_point_shapefile"] + self.attributes[f"{self.widget_key}_shapefile"] ) self.shapefile_layout.addWidget(self.shapefile_line_edit) self.shapefile_layout.addWidget(self.shapefile_button) @@ -157,20 +157,20 @@ def get_data(self) -> dict: layer = self.layer_combo.currentLayer() if not layer: - self.attributes["multi_buffer_point_layer"] = None + self.attributes[f"{self.widget_key}_layer"] = None else: - self.attributes["multi_buffer_point_layer_name"] = layer.name() - self.attributes["multi_buffer_point_layer_source"] = layer.source() - self.attributes["multi_buffer_point_layer_provider_type"] = ( + self.attributes[f"{self.widget_key}_layer_name"] = layer.name() + self.attributes[f"{self.widget_key}_layer_source"] = layer.source() + self.attributes[f"{self.widget_key}_layer_provider_type"] = ( layer.providerType() ) - self.attributes["multi_buffer_point_layer_crs"] = ( + self.attributes[f"{self.widget_key}_layer_crs"] = ( layer.crs().authid() ) # Coordinate Reference System - self.attributes["multi_buffer_point_layer_wkb_type"] = ( + self.attributes[f"{self.widget_key}_layer_wkb_type"] = ( layer.wkbType() ) # Geometry type (e.g., Point, Polygon) - self.attributes["multi_buffer_point_layer_id"] = ( + self.attributes[f"{self.widget_key}_layer_id"] = ( layer.id() ) # Unique ID of the layer @@ -185,7 +185,7 @@ def get_data(self) -> dict: self.attributes["multi_buffer_travel_units"] = "Time" self.attributes["multi_buffer_travel_distances"] = self.increments_input.text() - self.attributes["multi_buffer_point_shapefile"] = ( + self.attributes[f"{self.widget_key}_shapefile"] = ( self.shapefile_line_edit.text() ) diff --git a/geest/gui/widgets/combined_widgets/raster_reclassification_widget.py b/geest/gui/widgets/combined_widgets/raster_reclassification_widget.py index 9a385148..f4cf98d7 100644 --- a/geest/gui/widgets/combined_widgets/raster_reclassification_widget.py +++ b/geest/gui/widgets/combined_widgets/raster_reclassification_widget.py @@ -11,6 +11,7 @@ from qgis.core import ( QgsMapLayerProxyModel, QgsProject, + Qgis, ) from qgis.PyQt.QtCore import QSettings from .base_indicator_widget import BaseIndicatorWidget @@ -39,7 +40,7 @@ def add_internal_widgets(self) -> None: """ try: self.main_layout = QVBoxLayout() - self.widget_key = "use_environmental_hazards" + self.widget_key = "environmental_hazards" self.settings = QSettings() # Raster Layer Section diff --git a/geest/gui/widgets/combined_widgets/safety_raster_widget.py b/geest/gui/widgets/combined_widgets/safety_raster_widget.py index dbaf557a..3ebfd414 100644 --- a/geest/gui/widgets/combined_widgets/safety_raster_widget.py +++ b/geest/gui/widgets/combined_widgets/safety_raster_widget.py @@ -11,6 +11,7 @@ from qgis.core import ( QgsMapLayerProxyModel, QgsProject, + Qgis, ) from qgis.PyQt.QtCore import QSettings from geest.utilities import log_message @@ -39,7 +40,7 @@ def add_internal_widgets(self) -> None: """ try: self.main_layout = QVBoxLayout() - self.widget_key = "use_nighttime_lights" + self.widget_key = "nighttime_lights" self.settings = QSettings() # Raster Layer Section diff --git a/geest/gui/widgets/combined_widgets/single_buffer_distance_widget.py b/geest/gui/widgets/combined_widgets/single_buffer_distance_widget.py index c9e78c52..3aa621cd 100644 --- a/geest/gui/widgets/combined_widgets/single_buffer_distance_widget.py +++ b/geest/gui/widgets/combined_widgets/single_buffer_distance_widget.py @@ -26,6 +26,7 @@ def add_internal_widgets(self) -> None: """ try: self.main_layout = QVBoxLayout() + self.widget_key = "single_buffer_point" # Point Layer Combobox - Filtered to point layers self.point_layer_label = QLabel( @@ -38,12 +39,12 @@ def add_internal_widgets(self) -> None: self.main_layout.addWidget(self.layer_combo) # Set the selected QgsVectorLayer in QgsMapLayerComboBox - layer_id = self.attributes.get("single_buffer_point_layer_id", None) + layer_id = self.attributes.get(f"{self.widget_key}_layer_id", None) if layer_id: layer = QgsProject.instance().mapLayer(layer_id) if layer: self.layer_combo.setLayer(layer) - layer_id = self.attributes.get("single_buffer_point_layer_id") + layer_id = self.attributes.get(f"{self.widget_key}_layer_id") layer = QgsProject.instance().mapLayer(layer_id) if layer and isinstance(layer, QgsVectorLayer): @@ -55,9 +56,9 @@ def add_internal_widgets(self) -> None: self.shapefile_button = QToolButton() self.shapefile_button.setText("...") self.shapefile_button.clicked.connect(self.select_shapefile) - if self.attributes.get("single_buffer_point_layer_shapefile", False): + if self.attributes.get(f"{self.widget_key}_layer_shapefile", False): self.shapefile_line_edit.setText( - self.attributes["single_buffer_point_layer_shapefile"] + self.attributes[f"{self.widget_key}_layer_shapefile"] ) self.shapefile_layout.addWidget(self.shapefile_line_edit) self.shapefile_layout.addWidget(self.shapefile_button) @@ -72,7 +73,7 @@ def add_internal_widgets(self) -> None: self.buffer_distance_layout.addWidget(self.buffer_distance_input) default_distance = self.attributes.get("default_single_buffer_distance", 0) buffer_distance = self.attributes.get( - "single_buffer_point_layer_distance", default_distance + f"{self.widget_key}_layer_distance", default_distance ) if buffer_distance == 0: buffer_distance = default_distance @@ -127,27 +128,27 @@ def get_data(self) -> dict: layer = self.layer_combo.currentLayer() if not layer: - self.attributes["single_buffer_point_layer"] = None + self.attributes[f"{self.widget_key}_layer"] = None else: - self.attributes["single_buffer_point_layer_name"] = layer.name() - self.attributes["single_buffer_point_layer_source"] = layer.source() - self.attributes["single_buffer_point_layer_provider_type"] = ( + self.attributes[f"{self.widget_key}_layer_name"] = layer.name() + self.attributes[f"{self.widget_key}_layer_source"] = layer.source() + self.attributes[f"{self.widget_key}_layer_provider_type"] = ( layer.providerType() ) - self.attributes["single_buffer_point_layer_crs"] = ( + self.attributes[f"{self.widget_key}_layer_crs"] = ( layer.crs().authid() ) # Coordinate Reference System - self.attributes["single_buffer_point_layer_wkb_type"] = ( + self.attributes[f"{self.widget_key}_layer_wkb_type"] = ( layer.wkbType() ) # Geometry type (e.g., Point, Polygon) - self.attributes["single_buffer_point_layer_id"] = ( + self.attributes[f"{self.widget_key}_layer_id"] = ( layer.id() ) # Unique ID of the layer - self.attributes["single_buffer_point_layer_distance"] = ( + self.attributes[f"{self.widget_key}_layer_distance"] = ( self.buffer_distance_input.value() ) - self.attributes["single_buffer_point_layer_shapefile"] = ( + self.attributes[f"{self.widget_key}_layer_shapefile"] = ( self.shapefile_line_edit.text() ) diff --git a/geest/gui/widgets/datasource_widgets/raster_datasource_widget.py b/geest/gui/widgets/datasource_widgets/raster_datasource_widget.py index 83f727e2..80b2725f 100644 --- a/geest/gui/widgets/datasource_widgets/raster_datasource_widget.py +++ b/geest/gui/widgets/datasource_widgets/raster_datasource_widget.py @@ -8,6 +8,7 @@ from qgis.core import ( QgsMapLayerProxyModel, QgsProject, + Qgis, ) from qgis.PyQt.QtCore import QSettings from .base_datasource_widget import BaseDataSourceWidget