diff --git a/qt_ui/logging_handler.py b/qt_ui/logging_handler.py index 465e4cb1..a1f16560 100644 --- a/qt_ui/logging_handler.py +++ b/qt_ui/logging_handler.py @@ -1,5 +1,8 @@ +from __future__ import annotations + import logging import typing +from collections.abc import Iterator LogHook = typing.Callable[[str], None] @@ -15,6 +18,16 @@ class HookableInMemoryHandler(logging.Handler): self._log = "" self._hook = None + @staticmethod + def iter_registered_handlers( + logger: logging.Logger | None = None, + ) -> Iterator[HookableInMemoryHandler]: + if logger is None: + logger = logging.getLogger() + for handler in logger.handlers: + if isinstance(handler, HookableInMemoryHandler): + yield handler + @property def log(self) -> str: return self._log diff --git a/qt_ui/windows/QLiberationWindow.py b/qt_ui/windows/QLiberationWindow.py index 195a201b..3392dfe5 100644 --- a/qt_ui/windows/QLiberationWindow.py +++ b/qt_ui/windows/QLiberationWindow.py @@ -27,6 +27,7 @@ from game.theater import ControlPoint, MissionTarget, TheaterGroundObject from game.turnstate import TurnState from qt_ui import liberation_install from qt_ui.dialogs import Dialog +from qt_ui.logging_handler import HookableInMemoryHandler from qt_ui.models import GameModel from qt_ui.simcontroller import SimController from qt_ui.uiflags import UiFlags @@ -576,6 +577,10 @@ class QLiberationWindow(QMainWindow): self._cp_dialog = QBaseMenu2(None, cp, self.game_model) self._cp_dialog.show() + def _disconnect_log_signals(self) -> None: + for handler in HookableInMemoryHandler.iter_registered_handlers(): + handler.clearHook() + def _qsettings(self) -> QSettings: return QSettings("DCS Liberation", "Qt UI") @@ -597,6 +602,7 @@ class QLiberationWindow(QMainWindow): QMessageBox.Yes | QMessageBox.No, ) if result == QMessageBox.Yes: + self._disconnect_log_signals() self._save_window_geometry() super().closeEvent(event) self.dialog = None diff --git a/qt_ui/windows/logs/QLogsWindow.py b/qt_ui/windows/logs/QLogsWindow.py index ae3358bd..baebbee9 100644 --- a/qt_ui/windows/logs/QLogsWindow.py +++ b/qt_ui/windows/logs/QLogsWindow.py @@ -1,14 +1,13 @@ -import logging import typing from PySide6.QtCore import Signal +from PySide6.QtGui import QTextCursor, QIcon from PySide6.QtWidgets import ( QDialog, QPlainTextEdit, QVBoxLayout, QPushButton, ) -from PySide6.QtGui import QTextCursor, QIcon from qt_ui.logging_handler import HookableInMemoryHandler @@ -50,12 +49,17 @@ class QLogsWindow(QDialog): self.appendLogSignal.connect(self.appendLog) - self._logging_handler = None - logger = logging.getLogger() - for handler in logger.handlers: - if isinstance(handler, HookableInMemoryHandler): - self._logging_handler = handler - break + try: + # This assumes that there's never more than one in memory handler. We don't + # configure more than one by default, but logging is customizable with + # resources/logging.yaml. If someone adds a second in-memory handler, only + # the first one (in arbitrary order) will be shown. + self._logging_handler = next( + HookableInMemoryHandler.iter_registered_handlers() + ) + except StopIteration: + self._logging_handler = None + if self._logging_handler is not None: self.textbox.setPlainText(self._logging_handler.log) self.textbox.moveCursor(QTextCursor.End)