diff --git a/Furious/Widget/UserServersQTableWidget.py b/Furious/Widget/UserServersQTableWidget.py index 5e95510..b5653ef 100644 --- a/Furious/Widget/UserServersQTableWidget.py +++ b/Furious/Widget/UserServersQTableWidget.py @@ -45,6 +45,7 @@ import logging import icmplib import functools +import threading __all__ = ['UserServersQTableWidget'] @@ -811,6 +812,9 @@ def __init__(self, *args, **kwargs): # Distinguish double-click and activated self.doubleClickedFlag = False + + self.guiEditorMutex = threading.Lock() + # Signals self.itemChanged.connect(self.handleItemChanged) self.itemSelectionChanged.connect(self.handleItemSelectionChanged) @@ -914,38 +918,39 @@ def getGuiEditorByFactory(self, factory, **kwargs): @QtCore.Slot(QTableWidgetItem) def handleItemDoubleClicked(self, item: QTableWidgetItem): - self.doubleClickedFlag = True + with self.guiEditorMutex: + self.doubleClickedFlag = True - index = item.row() - factory = AS_UserServers()[index] + index = item.row() + factory = AS_UserServers()[index] - guiEditor = self.getGuiEditorByFactory(factory, translatable=False) + guiEditor = self.getGuiEditorByFactory(factory, translatable=False) - if guiEditor is None: - # Unrecognized. Do nothing - return + if guiEditor is None: + # Unrecognized. Do nothing + return - # Dummy ref - setattr(self, '_guiEditorRef0', guiEditor) + # Dummy ref + setattr(self, '_guiEditorRef0', guiEditor) - guiEditor.setWindowTitle(f'{index + 1} - ' + factory.getExtras('remark')) + guiEditor.setWindowTitle(f'{index + 1} - ' + factory.getExtras('remark')) - try: - guiEditor.factoryToInput(factory) - except Exception as ex: - # Any non-exit exceptions + try: + guiEditor.factoryToInput(factory) + except Exception as ex: + # Any non-exit exceptions - logger.error(f'error while converting factory to input: {ex}') + logger.error(f'error while converting factory to input: {ex}') - guiEditor.accepted.connect( - functools.partial( - self.handleGuiEditorAccepted, - guiEditor, - index, - factory, + guiEditor.accepted.connect( + functools.partial( + self.handleGuiEditorAccepted, + guiEditor, + index, + factory, + ) ) - ) - guiEditor.open() + guiEditor.open() def handleGuiEditorAccepted( self, @@ -953,26 +958,27 @@ def handleGuiEditorAccepted( index: int, factory: ConfigurationFactory, ): - logger.debug(f'guiEditor accepted with index {index}') + with self.guiEditorMutex: + logger.debug(f'guiEditor accepted with index {index}') - modified = editor.inputToFactory(factory) + modified = editor.inputToFactory(factory) - # Still flush to row since remark may be modified - self.flushRow(index, factory) + # Still flush to row since remark may be modified + self.flushRow(index, factory) - if modified and index == AS_UserActivatedItemIndex(): - try: - if APP().isSystemTrayConnected(): - mbox = NewChangesNextTimeMBox() + if modified and index == AS_UserActivatedItemIndex(): + try: + if APP().isSystemTrayConnected(): + mbox = NewChangesNextTimeMBox() - # Show the MessageBox asynchronously - mbox.open() - except Exception: - # Any non-exit exceptions + # Show the MessageBox asynchronously + mbox.open() + except Exception: + # Any non-exit exceptions - pass + pass - editor.accepted.disconnect() + editor.accepted.disconnect() @QtCore.Slot(QtCore.QPoint) def handleCustomContextMenuRequested(self, point): @@ -1073,45 +1079,47 @@ def addServerViaGui( windowTitle: str = APPLICATION_NAME, **kwargs, ): - factory = getEmptyFactory(protocol) + with self.guiEditorMutex: + factory = getEmptyFactory(protocol) - guiEditor = self.getGuiEditorByFactory(factory, **kwargs) + guiEditor = self.getGuiEditorByFactory(factory, **kwargs) - if guiEditor is None: - # Unrecognized. Do nothing - return + if guiEditor is None: + # Unrecognized. Do nothing + return - # Dummy ref - setattr(self, '_guiEditorRef1', guiEditor) + # Dummy ref + setattr(self, '_guiEditorRef1', guiEditor) - guiEditor.setWindowTitle(windowTitle) + guiEditor.setWindowTitle(windowTitle) - try: - guiEditor.factoryToInput(factory) - except Exception as ex: - # Any non-exit exceptions + try: + guiEditor.factoryToInput(factory) + except Exception as ex: + # Any non-exit exceptions - logger.error(f'error while converting factory to input: {ex}') + logger.error(f'error while converting factory to input: {ex}') - guiEditor.accepted.connect( - functools.partial( - self.handleAddServerViaGui, - guiEditor, - factory, + guiEditor.accepted.connect( + functools.partial( + self.handleAddServerViaGui, + guiEditor, + factory, + ) ) - ) - guiEditor.open() + guiEditor.open() def handleAddServerViaGui( self, editor: GuiEditorWidgetQDialog, factory: ConfigurationFactory, ): - editor.inputToFactory(factory) + with self.guiEditorMutex: + editor.inputToFactory(factory) - self.appendNewItemByFactory(factory) + self.appendNewItemByFactory(factory) - editor.accepted.disconnect() + editor.accepted.disconnect() def flushRow(self, row: int, item: ConfigurationFactory): for column in list(range(self.columnCount())):