From 0c316b961a7d6e32eb2146abc04f0120cf4189a6 Mon Sep 17 00:00:00 2001 From: wwelch <57472892+ww2406@users.noreply.github.com> Date: Sat, 12 Oct 2024 21:44:38 -0700 Subject: [PATCH] Add fix for #648 with error message during import This fixes #648 by adding a command tracker queue. When the queue is not empty, closing the dialog is prevented to ensure the completion callback can still access UI elements. --- gui/wxpython/modules/import_export.py | 43 +++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/gui/wxpython/modules/import_export.py b/gui/wxpython/modules/import_export.py index f2f70e47831..ded580e754f 100644 --- a/gui/wxpython/modules/import_export.py +++ b/gui/wxpython/modules/import_export.py @@ -21,6 +21,7 @@ """ import os +from collections import deque from pathlib import Path @@ -60,6 +61,8 @@ def __init__( self.commandId = -1 # id of running command + self._commands_running = deque() + wx.Dialog.__init__( self, parent, id, title, style=style, name="MultiImportDialog" ) @@ -122,8 +125,9 @@ def __init__( # buttons # # cancel + self._DEFAULT_CLOSE_BTN_TEXT = "Close dialog" self.btn_close = CloseButton(parent=self.panel) - self.btn_close.SetToolTip(_("Close dialog")) + self.btn_close.SetToolTip(_(self._DEFAULT_CLOSE_BTN_TEXT)) self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose) # run self.btn_run = Button(parent=self.panel, id=wx.ID_OK, label=_("&Import")) @@ -131,7 +135,7 @@ def __init__( self.btn_run.SetDefault() self.btn_run.Bind(wx.EVT_BUTTON, self.OnRun) - self.Bind(wx.EVT_CLOSE, lambda evt: self.Destroy()) + self.Bind(wx.EVT_CLOSE, self._handleCloseEvent) self.notebook = GNotebook(parent=self, style=globalvar.FNPageDStyle) @@ -270,6 +274,30 @@ def _validateOutputMapName(self): return False return True + def _handleCloseEvent(self, *args, **kwargs): + if len(self._commands_running) > 0: + # prevent dialog close while async commands are running + return + self.Destroy() + + def _addToCommandQueue(self): + self._commands_running.append(True) + + # disable the dialog close button + self.btn_close.SetToolTip(_("Dialog cannot be closed while command is running.")) + self.btn_close.Disable() + + def _removeFromCommandQueue(self): + try: + self._commands_running.pop() + except IndexError: + pass + finally: + if len(self._commands_running) == 0: + # enable the dialog close button + self.btn_close.Enable() + self.btn_close.SetToolTip(self._DEFAULT_CLOSE_BTN_TEXT) + def OnClose(self, event=None): """Close dialog""" self.Close() @@ -519,6 +547,7 @@ def OnRun(self, event): ): cmd.append("--overwrite") + self._addToCommandQueue() # run in Layer Manager self._giface.RunCmd( cmd, onDone=self.OnCmdDone, userData=userData, addLayer=False @@ -527,9 +556,11 @@ def OnRun(self, event): def OnCmdDone(self, event): """Load layers and close if required""" if not hasattr(self, "AddLayers"): + self._removeFromCommandQueue() return self.AddLayers(event.returncode, event.cmd, event.userData) + self._removeFromCommandQueue() if event.returncode == 0 and self.closeOnFinish.IsChecked(): self.Close() @@ -670,6 +701,7 @@ def OnRun(self, event): ): cmd.append("--overwrite") + self._addToCommandQueue() # run in Layer Manager self._giface.RunCmd( cmd, onDone=self.OnCmdDone, userData=userData, addLayer=False @@ -678,10 +710,13 @@ def OnRun(self, event): def OnCmdDone(self, event): """Load layers and close if required""" if not hasattr(self, "AddLayers"): + self._removeFromCommandQueue() return self.AddLayers(event.returncode, event.cmd, event.userData) + self._removeFromCommandQueue() + if self.popOGR: os.environ.pop("GRASS_VECTOR_OGR") @@ -880,16 +915,20 @@ def OnRun(self, event): ): cmd.append("--overwrite") + self._commands_running.append(True) # run in Layer Manager self._giface.RunCmd(cmd, onDone=self.OnCmdDone, addLayer=False) def OnCmdDone(self, event): """Load layers and close if required""" if not hasattr(self, "AddLayers"): + self._removeFromCommandQueue() return self.AddLayers(event.returncode, event.cmd) + self._removeFromCommandQueue() + if self.closeOnFinish.IsChecked(): self.Close()