From 4fb91dc56e383707a20e0352377a5e7f0828c1ae Mon Sep 17 00:00:00 2001 From: Ricardo Garcia Silva Date: Wed, 6 Nov 2024 00:13:25 +0000 Subject: [PATCH] Fixed unloading plugin crashing QGIS This was due to an incorrect use of iface.removePluginVectorMenu() --- CHANGELOG.md | 3 +++ src/qgis_conefor/main.py | 38 ++++++++++++++++++++++---------------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de08572..5c7a4ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Name of node file changed to not mention name of autogenerated attribute (in order to make filename shorter) +### Fixed +- Fixed plugin reload crashing QGIS due to erroneous removal of menu entry + ## [2.0.0-rc8] - 2024-10-26 diff --git a/src/qgis_conefor/main.py b/src/qgis_conefor/main.py index 621aedf..04b253d 100644 --- a/src/qgis_conefor/main.py +++ b/src/qgis_conefor/main.py @@ -64,8 +64,7 @@ class QgisConefor: action: QtWidgets.QAction dialog: Optional[QtWidgets.QDialog] - processing_provider: ProcessingConeforProvider - algorithm: Optional[qgis.core.QgsProcessingAlgorithm] + processing_provider: Optional[ProcessingConeforProvider] model: Optional[ProcessLayerTableModel] processing_context: Optional[qgis.core.QgsProcessingContext] _processing_tasks: dict[ @@ -79,35 +78,33 @@ class QgisConefor: def __init__(self, iface: qgis.gui.QgisInterface): self.iface = iface self.dialog = None - self.model = ProcessLayerTableModel( - qgis_layers={}, - initial_layers_to_process=[], - lock_layers=False, - dialog=None - ) - self.processing_provider = ProcessingConeforProvider() + self.model = None + self.processing_provider = None self.processing_context = None - self.algorithm = None self._processing_tasks = {} self._task_results = {} def init_processing(self): + self.processing_provider = ProcessingConeforProvider() processing_registry = qgis.core.QgsApplication.processingRegistry() processing_registry.addProvider(self.processing_provider) def initGui(self): self.init_processing() - processing_registry = qgis.core.QgsApplication.processingRegistry() - self.algorithm = processing_registry.createAlgorithmById( - "conefor:inputsfrompolygon") self.analyzer_task = None + self.model = ProcessLayerTableModel( + qgis_layers={}, + initial_layers_to_process=[], + lock_layers=False, + dialog=None + ) self.dialog = ConeforDialog(self, model=self.model) self.dialog.setModal(True) self.dialog.finished.connect(self.handle_dialog_closed) self.dialog.accepted.connect(self.prepare_conefor_inputs) self.action = QtWidgets.QAction( QtGui.QIcon(schemas.ICON_RESOURCE_PATH), - self._action_title, + f"&{self._action_title}", self.iface.mainWindow() ) self.action.triggered.connect(self.run) @@ -115,16 +112,22 @@ def initGui(self): self.iface.addPluginToVectorMenu(None, self.action) self.iface.addVectorToolBarIcon(self.action) qgis_project = qgis.core.QgsProject.instance() + self.start_tracking_layers(new_layers=qgis_project.mapLayers().values()) qgis_project.legendLayersAdded.connect(self.start_tracking_layers) qgis_project.layersRemoved.connect(self.check_for_removed_layers) def unload(self): + # return processing_registry = qgis.core.QgsApplication.processingRegistry() processing_registry.removeProvider(self.processing_provider) qgis_project = qgis.core.QgsProject.instance() qgis_project.legendLayersAdded.disconnect(self.start_tracking_layers) qgis_project.layersRemoved.disconnect(self.check_for_removed_layers) - self.iface.removePluginVectorMenu(f"&{self._action_title}", self.action) + self.action.triggered.disconnect(self.run) + # iface.removePluginVectorMenu() does not work here because it assumes it + # is dealing with a menu, not a single action + vector_menu = self.iface.vectorMenu() + vector_menu.removeAction(self.action) self.iface.removeVectorToolBarIcon(self.action) def start_analyzing_layers(self, disregard_ids: Optional[list[str]] = None) -> None: @@ -188,8 +191,11 @@ def _process_layer( ) connection_method = ConeforInputsPolygon._NODE_DISTANCE_CHOICES.index( layer_params.connections_method.value) + processing_registry = qgis.core.QgsApplication.processingRegistry() + algorithm = processing_registry.createAlgorithmById( + "conefor:inputsfrompolygon") task = qgis.core.QgsProcessingAlgRunnerTask( - algorithm=self.algorithm, + algorithm=algorithm, parameters={ ConeforInputsPolygon.INPUT_NODE_IDENTIFIER_NAME[0]: ( layer_params.id_attribute_field_name or ""),