Fix race condition in guiEditor

Signed-off-by: Loren Eteval <loren.eteval@proton.me>
This commit is contained in:
Loren Eteval
2024-05-11 20:32:42 +08:00
parent 59773b4cae
commit 0317ed79af
+68 -60
View File
@@ -45,6 +45,7 @@ import queue
import logging
import icmplib
import functools
import threading
__all__ = ['UserServersQTableWidget']
@@ -811,6 +812,9 @@ class UserServersQTableWidget(QTranslatable, AppQTableWidget):
# 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 @@ class UserServersQTableWidget(QTranslatable, AppQTableWidget):
@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 @@ class UserServersQTableWidget(QTranslatable, AppQTableWidget):
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 @@ class UserServersQTableWidget(QTranslatable, AppQTableWidget):
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())):