154 lines
6.6 KiB
Python
154 lines
6.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
# hub/ticket/ui/pages/document_browser_page.py
|
|
|
|
"""Общая страница просмотра документов Ticket."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from gui.components import Button, Label, TextInput
|
|
from gui.containers import HContainer, SContainer, VContainer
|
|
|
|
from application import TaskApplicationService
|
|
from domain import TicketDocumentSnapshot
|
|
from ui.ticket_selection_list import TicketSelectionEntry, TicketSelectionList
|
|
from .report_viewer import ReportViewer
|
|
|
|
|
|
class DocumentBrowserPage(SContainer):
|
|
"""Базовая страница списка документов и предпросмотра."""
|
|
|
|
def __init__(
|
|
self,
|
|
application: TaskApplicationService,
|
|
title: str,
|
|
empty_message: str,
|
|
document_type: str,
|
|
parent=None,
|
|
):
|
|
super().__init__(width_percent=100, height_percent=100, parent=parent)
|
|
self._application = application
|
|
self._title = title
|
|
self._empty_message = empty_message
|
|
self._document_type = document_type
|
|
self._documents: dict[str, TicketDocumentSnapshot] = {}
|
|
self._list_widget: TicketSelectionList | None = None
|
|
self._preview: TextInput | None = None
|
|
self._open_button: Button | None = None
|
|
self._setup_ui()
|
|
self._connect_signals()
|
|
self._reload_documents()
|
|
|
|
def _setup_ui(self) -> None:
|
|
# Root-контейнер страницы документов: заголовок плюс двухпанельная область.
|
|
main_container = VContainer(margin=12, spacing=10, parent=self)
|
|
title_label = Label(self._title, alignment="left", style="TICKET_LIST_HEADER")
|
|
# Content-row документов: раскладывает список документов и их предпросмотр.
|
|
content_row = HContainer(spacing=10, parent=main_container)
|
|
|
|
# Левая панель списка документов
|
|
list_panel = SContainer(style="TICKET_LIST_CONTAINER")
|
|
# List-layout: внутренний контейнер заголовка и списка документов.
|
|
list_layout = VContainer(margin=12, spacing=8, parent=list_panel)
|
|
list_title_label = Label("Список документов",
|
|
margin=[0, 0, 0, 8],
|
|
alignment="left",
|
|
style="TICKET_LIST_TITLE")
|
|
|
|
self._list_widget = TicketSelectionList()
|
|
list_layout.add_widget(list_title_label)
|
|
list_layout.add_widget(self._list_widget)
|
|
|
|
# Правая панель предпросмотра
|
|
preview_panel = SContainer(style="TICKET_LIST_CONTAINER")
|
|
# Preview-layout: внутренний контейнер заголовка, preview-поля и кнопки открытия.
|
|
preview_layout = VContainer(margin=12, spacing=8, parent=preview_panel)
|
|
preview_title_label = Label("Предпросмотр", alignment="left", style="TICKET_LIST_TITLE")
|
|
self._preview = TextInput(style="TICKET_PREVIEW_AREA", multiline=True)
|
|
self._preview.set_read_only(True)
|
|
self._open_button = Button("Открыть документ", style="FILTER_BUTTON", content_fit=True)
|
|
self._open_button.set_enabled(False)
|
|
preview_layout.add_widget(preview_title_label)
|
|
preview_layout.add_widget(self._preview)
|
|
preview_layout.add_widget(self._open_button)
|
|
|
|
content_row.add_widget_with_stretch(list_panel, 4)
|
|
content_row.add_widget_with_stretch(preview_panel, 7)
|
|
main_container.add_widget(title_label)
|
|
main_container.add_widget(content_row)
|
|
|
|
def _connect_signals(self) -> None:
|
|
# Application-состояние
|
|
self._application.task_updated.connect(self._reload_documents)
|
|
self._application.state_loaded.connect(self._reload_documents)
|
|
|
|
# UI-события страницы
|
|
if self._list_widget is not None:
|
|
self._list_widget.selection_changed.connect(self._update_preview)
|
|
self._list_widget.item_activated.connect(self._open_current_document)
|
|
if self._open_button is not None:
|
|
self._open_button.clicked.connect(self._open_current_document)
|
|
|
|
def _reload_documents(self, *_args) -> None:
|
|
if self._list_widget is None or self._preview is None:
|
|
return
|
|
current_document_id = self._current_document_id()
|
|
self._documents = {
|
|
document.document_id: document
|
|
for document in self._application.list_documents(self._document_type)
|
|
}
|
|
entries = [
|
|
TicketSelectionEntry(
|
|
entry_id=document.document_id,
|
|
title=document.title,
|
|
subtitle=document.created_at.strftime("%d.%m.%Y %H:%M"),
|
|
)
|
|
for document in self._documents.values()
|
|
]
|
|
self._list_widget.set_entries(entries)
|
|
if not self._documents:
|
|
self._preview.set_text(self._empty_message)
|
|
if self._open_button is not None:
|
|
self._open_button.set_enabled(False)
|
|
return
|
|
self._restore_selection(current_document_id)
|
|
self._update_preview()
|
|
|
|
def _restore_selection(self, document_id: str | None) -> None:
|
|
if self._list_widget is None:
|
|
return
|
|
self._list_widget.set_current_entry(document_id)
|
|
|
|
def _update_preview(self, *_args) -> None:
|
|
if self._preview is None:
|
|
return
|
|
document = self._current_document()
|
|
if document is None:
|
|
self._preview.set_text(self._empty_message)
|
|
if self._open_button is not None:
|
|
self._open_button.set_enabled(False)
|
|
return
|
|
self._preview.set_text(document.content or document.summary or document.title)
|
|
if self._open_button is not None:
|
|
self._open_button.set_enabled(True)
|
|
|
|
def _current_document(self) -> TicketDocumentSnapshot | None:
|
|
document_id = self._current_document_id()
|
|
if document_id is None:
|
|
return None
|
|
return self._documents.get(document_id)
|
|
|
|
def _current_document_id(self) -> str | None:
|
|
if self._list_widget is None:
|
|
return None
|
|
entry_id = self._list_widget.current_entry_id()
|
|
return str(entry_id) if entry_id is not None else None
|
|
|
|
def _open_current_document(self, *_args) -> None:
|
|
document = self._current_document()
|
|
if document is not None:
|
|
ReportViewer(document, parent=self).exec()
|
|
|
|
def showEvent(self, event) -> None:
|
|
super().showEvent(event)
|
|
self._reload_documents()
|