diff --git a/qt_ui/windows/QLiberationWindow.py b/qt_ui/windows/QLiberationWindow.py index 1cc946fd..a2c984d2 100644 --- a/qt_ui/windows/QLiberationWindow.py +++ b/qt_ui/windows/QLiberationWindow.py @@ -37,6 +37,7 @@ from qt_ui.windows.preferences.QLiberationPreferencesWindow import ( from qt_ui.windows.settings.QSettingsWindow import QSettingsWindow from qt_ui.windows.stats.QStatsWindow import QStatsWindow from qt_ui.windows.notes.QNotesWindow import QNotesWindow +from qt_ui.windows.logs.QLogsWindow import QLogsWindow class QLiberationWindow(QMainWindow): @@ -151,6 +152,9 @@ class QLiberationWindow(QMainWindow): ) ) + self.openLogsAction = QAction("Show &logs", self) + self.openLogsAction.triggered.connect(self.showLogsDialog) + self.openSettingsAction = QAction("Settings", self) self.openSettingsAction.setIcon(CONST.ICONS["Settings"]) self.openSettingsAction.triggered.connect(self.showSettingsDialog) @@ -210,6 +214,7 @@ class QLiberationWindow(QMainWindow): help_menu.addAction( "Report an &issue", lambda: webbrowser.open_new_tab(URLS["Issues"]) ) + help_menu.addAction(self.openLogsAction) help_menu.addSeparator() help_menu.addAction(self.showAboutDialogAction) @@ -361,6 +366,10 @@ class QLiberationWindow(QMainWindow): self.dialog = QNotesWindow(self.game) self.dialog.show() + def showLogsDialog(self): + self.dialog = QLogsWindow() + self.dialog.show() + def onDebriefing(self, debrief: Debriefing): logging.info("On Debriefing") self.debriefing = QDebriefingWindow(debrief) diff --git a/qt_ui/windows/logs/QLogsWindow.py b/qt_ui/windows/logs/QLogsWindow.py new file mode 100644 index 00000000..936261a1 --- /dev/null +++ b/qt_ui/windows/logs/QLogsWindow.py @@ -0,0 +1,67 @@ +import logging +import typing + +from PySide2.QtWidgets import ( + QDialog, + QPlainTextEdit, + QVBoxLayout, + QPushButton, +) +from PySide2.QtGui import QTextCursor + +from qt_ui.logging_handler import HookableInMemoryHandler + + +class QLogsWindow(QDialog): + vbox: QVBoxLayout + textbox: QPlainTextEdit + clear_button: QPushButton + _logging_handler: typing.Optional[HookableInMemoryHandler] + + def __init__(self): + super().__init__() + + self.setWindowTitle("Logs") + self.setMinimumSize(400, 100) + self.resize(1000, 450) + + self.vbox = QVBoxLayout() + self.setLayout(self.vbox) + + self.textbox = QPlainTextEdit(self) + self.textbox.setReadOnly(True) + self.textbox.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap) + self.textbox.move(10, 10) + self.textbox.resize(1000, 450) + self.textbox.setStyleSheet( + "font-family: 'Courier New', monospace; background: #1D2731;" + ) + self.vbox.addWidget(self.textbox) + + self.clear_button = QPushButton(self) + self.clear_button.setText("CLEAR") + self.clear_button.setProperty("style", "btn-primary") + self.clear_button.clicked.connect(self.clearLogs) + self.vbox.addWidget(self.clear_button) + + self._logging_handler = None + logger = logging.getLogger() + for handler in logger.handlers: + if isinstance(handler, HookableInMemoryHandler): + self._logging_handler = handler + break + if self._logging_handler is not None: + self.textbox.setPlainText(self._logging_handler.log) + self.textbox.moveCursor(QTextCursor.End) + self._logging_handler.setHook(self.appendLog) + else: + self.textbox.setPlainText("WARNING: logging not initialized!") + + def clearLogs(self) -> None: + if self._logging_handler is not None: + self._logging_handler.clearLog() + self.textbox.setPlainText("") + + def appendLog(self, msg: str): + self.textbox.appendPlainText(msg) + self.textbox.moveCursor(QTextCursor.End)