Skip to content

Commit 3dc9620

Browse files
authored
Fix QGIS plugin reload cleanup (#529)
1 parent 42a35b0 commit 3dc9620

1 file changed

Lines changed: 97 additions & 1 deletion

File tree

qgis-samgeo-plugin/samgeo_plugin.py

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from qgis.PyQt.QtGui import QIcon
99
from qgis.PyQt.QtWidgets import (
1010
QAction,
11+
QToolBar,
1112
QDockWidget,
1213
QWidget,
1314
QVBoxLayout,
@@ -41,6 +42,9 @@
4142
from .map_tools import PointPromptTool, BoxPromptTool
4243

4344

45+
TOOLBAR_OBJECT_NAME = "SamGeo"
46+
MENU_TITLE = "&SamGeo"
47+
4448
class SamGeoPlugin:
4549
"""QGIS Plugin for remote sensing image segmentation using SamGeo."""
4650

@@ -57,8 +61,10 @@ def __init__(self, iface):
5761
# Initialize plugin attributes
5862
self.actions = []
5963
self.menu = "&SamGeo"
64+
self._remove_toolbars_by_object_name()
65+
self._remove_menus_by_title()
6066
self.toolbar = self.iface.addToolBar("SamGeo")
61-
self.toolbar.setObjectName("SamGeo")
67+
self.toolbar.setObjectName(TOOLBAR_OBJECT_NAME)
6268

6369
# Dock widget
6470
self.dock_widget = None
@@ -133,6 +139,93 @@ def initGui(self):
133139
status_tip=self.tr("Open SamGeo Segmentation Panel"),
134140
)
135141

142+
143+
def _remove_toolbar(self, toolbar):
144+
"""Detach and schedule deletion of a plugin toolbar widget."""
145+
if toolbar is None:
146+
return
147+
148+
main_window = self.iface.mainWindow()
149+
actions = []
150+
try:
151+
actions = list(toolbar.actions())
152+
except Exception:
153+
pass # nosec B110
154+
try:
155+
toolbar.clear()
156+
except Exception:
157+
pass # nosec B110
158+
for action in actions:
159+
try:
160+
action.deleteLater()
161+
except Exception:
162+
pass # nosec B110
163+
try:
164+
main_window.removeToolBar(toolbar)
165+
except Exception:
166+
pass # nosec B110
167+
try:
168+
toolbar.hide()
169+
except Exception:
170+
pass # nosec B110
171+
try:
172+
toolbar.setParent(None)
173+
except Exception:
174+
pass # nosec B110
175+
try:
176+
toolbar.deleteLater()
177+
except Exception:
178+
pass # nosec B110
179+
180+
def _remove_toolbars_by_object_name(self):
181+
"""Remove current or stale plugin toolbars from QGIS."""
182+
main_window = self.iface.mainWindow()
183+
for toolbar in main_window.findChildren(QToolBar, TOOLBAR_OBJECT_NAME):
184+
self._remove_toolbar(toolbar)
185+
186+
def _plugin_menu_titles(self):
187+
"""Return possible translated and untranslated plugin menu titles."""
188+
titles = {MENU_TITLE}
189+
translator = getattr(self, "tr", None)
190+
if callable(translator):
191+
try:
192+
titles.add(translator(MENU_TITLE))
193+
except Exception:
194+
pass # nosec B110
195+
return titles
196+
197+
def _remove_menu(self, menu):
198+
"""Detach and schedule deletion of a plugin menu."""
199+
if menu is None:
200+
return
201+
202+
main_window = self.iface.mainWindow()
203+
try:
204+
menu.clear()
205+
except Exception:
206+
pass # nosec B110
207+
try:
208+
main_window.menuBar().removeAction(menu.menuAction())
209+
except Exception:
210+
pass # nosec B110
211+
try:
212+
menu.setParent(None)
213+
except Exception:
214+
pass # nosec B110
215+
try:
216+
menu.deleteLater()
217+
except Exception:
218+
pass # nosec B110
219+
220+
def _remove_menus_by_title(self):
221+
"""Remove current or stale plugin menus from QGIS."""
222+
menu_bar = self.iface.mainWindow().menuBar()
223+
titles = self._plugin_menu_titles()
224+
for action in menu_bar.actions():
225+
menu = action.menu()
226+
if menu is not None and menu.title() in titles:
227+
self._remove_menu(menu)
228+
136229
def unload(self):
137230
"""Remove the plugin menu item and icon from QGIS GUI."""
138231
for action in self.actions:
@@ -151,6 +244,9 @@ def unload(self):
151244
del self.sam
152245
self.sam = None
153246

247+
self._remove_toolbars_by_object_name()
248+
self._remove_menus_by_title()
249+
154250
def run(self):
155251
"""Run the plugin - show the dock widget."""
156252
if self.dock_widget is None:

0 commit comments

Comments
 (0)