Files
Dispatch/Dispatch_V0.1.1/window.py
2026-04-29 08:18:54 +04:00

105 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
# dispatch/window.py
"""Главное окно независимого приложения Dispatch.
Назначение модуля:
Минимальный графический каркас, выполняющий единственную обязанность —
разместить корневой виджет модуля `hub.ticket.TicketPlugin` в окне
верхнего уровня. Управление содержимым модуля Ticket остаётся
полностью внутри самого модуля.
Архитектурные ограничения:
- Окно не содержит предметной логики и не обращается к внутренним
полям модуля Ticket: взаимодействие выполняется только через его
публичный API (`TicketPlugin`).
- Стилевое оформление берётся из внешнего реестра `APP_STYLES`;
локальные QSS-литералы запрещены (правило 6.3).
- Отказ модуля Ticket изолирован: при ошибке инициализации окно
продолжает существовать, ошибка фиксируется в журнале.
"""
from PySide6.QtCore import Qt, QEvent, QTimer
from PySide6.QtWidgets import QMainWindow
from error_logger import log_exception
from gui.containers.percent_sized_widget import PercentSizedWidget
from gui.styles import APP_STYLES
from gui.theme_bus import theme_bus as _default_theme_bus
from application import TaskApplicationService
from ticket_plugin import TicketPlugin
from null_hardware_gateway import NullHardwareGateway
class DispatchMainWindow(QMainWindow):
"""Главное окно приложения Dispatch с единственным модулем Ticket."""
def __init__(self, theme_bus=None):
super().__init__()
self._theme_bus = theme_bus or _default_theme_bus
self._ticket_plugin: TicketPlugin | None = None
self._setup_window()
self._setup_ui()
self._connect_signals()
def _setup_window(self) -> None:
"""Настроить параметры окна верхнего уровня."""
self.setWindowTitle("Dispatch — Ticket")
self.setMinimumSize(1200, 800)
self.setStyleSheet(APP_STYLES.get("MAIN_WINDOW_DARK", ""))
self.showMaximized()
def _setup_ui(self) -> None:
"""Разместить корневой виджет модуля Ticket в качестве центрального.
В составе Dispatch модуль работы с COM-портом отключён: приложение
собирает application-сервис Ticket с null-шлюзом и передаёт его
в `TicketPlugin`, который владеет жизненным циклом сервиса.
"""
try:
null_gateway = NullHardwareGateway(parent=self)
application_service = TaskApplicationService(
hardware_gateway=null_gateway,
parent=self,
)
self._ticket_plugin = TicketPlugin(application_service=application_service)
self.setCentralWidget(self._ticket_plugin)
except Exception as exc:
log_exception(__name__, "DispatchMainWindow._setup_ui", exc)
raise
def _connect_signals(self) -> None:
"""Подключить шину тем для согласованного оформления окна."""
self._theme_bus.theme_changed.connect(self._on_theme_changed)
def _on_theme_changed(self, theme: str) -> None:
"""Применить тему окна по ключам из внешнего реестра стилей."""
is_light = str(theme or "").strip().lower() == "light"
key = "MAIN_WINDOW_LIGHT" if is_light else "MAIN_WINDOW_DARK"
self.setStyleSheet(APP_STYLES.get(key, ""))
def changeEvent(self, event):
"""Пересчитать процентную разметку при восстановлении окна."""
if event.type() == QEvent.Type.WindowStateChange:
if not (self.windowState() & Qt.WindowState.WindowMinimized):
QTimer.singleShot(0, self._refresh_percent_layout)
return super().changeEvent(event)
def _refresh_percent_layout(self) -> None:
"""Принудительно пересчитать процентные размеры дочерних виджетов."""
for widget in self.findChildren(PercentSizedWidget):
try:
widget.schedule_percent_update()
except Exception as exc:
log_exception(__name__, "DispatchMainWindow._refresh_percent_layout", exc)
def closeEvent(self, event) -> None:
"""Гарантировать корректную остановку модуля Ticket при закрытии."""
if self._ticket_plugin is not None:
try:
self._ticket_plugin.cleanup()
except Exception as exc:
log_exception(__name__, "DispatchMainWindow.closeEvent", exc)
super().closeEvent(event)