132 lines
6.8 KiB
Python
132 lines
6.8 KiB
Python
# -*- coding: utf-8 -*-
|
||
# gui/components/model_view/_mv_presentation.py
|
||
"""Фасад видимости сцены для применения декларативных спецификаций представления."""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import TYPE_CHECKING
|
||
|
||
from error_logger import log_exception
|
||
|
||
if TYPE_CHECKING:
|
||
from gui.components.model_view_widget import ModelViewWidget
|
||
|
||
|
||
class ScenePresentationMixin:
|
||
"""Применение спецификаций видимости сцены через публичный API ModelView."""
|
||
|
||
@staticmethod
|
||
def _safe_call(fn, *args, **kwargs):
|
||
try:
|
||
return fn(*args, **kwargs)
|
||
except Exception as exc:
|
||
log_exception(__name__, "ScenePresentationMixin._safe_call", exc)
|
||
return None
|
||
|
||
@staticmethod
|
||
def _rack_filter_value(spec) -> str:
|
||
rack_filter = getattr(spec, "rack_filter", "")
|
||
return str(getattr(rack_filter, "value", rack_filter) or "")
|
||
|
||
def apply_scene_spec(
|
||
self: "ModelViewWidget",
|
||
spec,
|
||
*,
|
||
start_select_rack: bool = False,
|
||
select_rack_id: str | None = None,
|
||
) -> None:
|
||
"""Применить ``SceneVisibilitySpec``, созданный политикой представления."""
|
||
if self is None or spec is None:
|
||
return
|
||
|
||
zone_contour_id = getattr(spec, "zone_contour_id", None)
|
||
if zone_contour_id:
|
||
self._safe_call(self.show_zone_contour, zone_contour_id)
|
||
elif bool(getattr(spec, "zone_solids_visible", False)):
|
||
self._safe_call(self.show_all_zones)
|
||
|
||
if bool(getattr(spec, "use_facility_contour_mode", False)) and hasattr(
|
||
self, "set_zone_facility_contour_mode"
|
||
):
|
||
zone_ids = [str(zid) for zid in getattr(self, "_zones", {}).keys()]
|
||
for zid in zone_ids:
|
||
has_racks = self.has_racks_in_zone(zid) if hasattr(self, "has_racks_in_zone") else False
|
||
self._safe_call(self.set_zone_facility_contour_mode, zid, has_racks)
|
||
|
||
if bool(getattr(spec, "hide_empty_zones", False)) and hasattr(self, "has_racks_in_zone"):
|
||
zone_ids = [str(zid) for zid in getattr(self, "_zones", {}).keys()]
|
||
for zid in zone_ids:
|
||
if not self.has_racks_in_zone(zid):
|
||
self._safe_call(self.set_zone_visibility, zid, False)
|
||
else:
|
||
self._safe_call(self.set_zone_facility_contour_mode, zid, False)
|
||
self._safe_call(self.set_zone_visibility, zid, False)
|
||
|
||
self._safe_call(self.set_zone_pick_enabled, bool(getattr(spec, "zone_pick_enabled", True)))
|
||
|
||
rack_filter = self._rack_filter_value(spec)
|
||
rack_zone_id = getattr(spec, "rack_zone_id", None)
|
||
rack_id = getattr(spec, "rack_id", None)
|
||
if rack_filter == "single_rack":
|
||
isolated = False
|
||
if hasattr(self, "show_only_rack") and rack_id:
|
||
isolated = bool(self._safe_call(self.show_only_rack, rack_id, rack_zone_id))
|
||
if not isolated and rack_zone_id:
|
||
self._safe_call(self.show_only_zone_racks, rack_zone_id)
|
||
elif rack_filter == "zone_only":
|
||
self._safe_call(self.show_only_zone_racks, rack_zone_id)
|
||
else:
|
||
self._safe_call(self.show_all_racks)
|
||
|
||
rack_select_mode = bool(getattr(spec, "rack_select_mode", False))
|
||
if rack_select_mode and start_select_rack and rack_zone_id:
|
||
self._safe_call(self.start_select_rack_mode, rack_zone_id)
|
||
elif not rack_select_mode:
|
||
self._safe_call(self.stop_select_rack_mode)
|
||
|
||
if select_rack_id and hasattr(self, "select_rack_by_id"):
|
||
self._safe_call(self.select_rack_by_id, select_rack_id, rack_zone_id)
|
||
|
||
if bool(getattr(spec, "clear_hover", False)):
|
||
mgr = getattr(self, "_interaction_manager", None)
|
||
if mgr is not None:
|
||
self._safe_call(mgr.reset)
|
||
|
||
self._safe_call(self.set_top_view_navigation, bool(getattr(spec, "top_view_navigation", False)))
|
||
if hasattr(self, "update_scene"):
|
||
self._safe_call(self.update_scene)
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Module workflow notes
|
||
# ---------------------------------------------------------------------------
|
||
# 1) Задача модуля:
|
||
# Применение наборов параметров отображения сцены и безопасный вызов методов представления.
|
||
#
|
||
# 2) Последовательность действий и вызовов:
|
||
# A. Класс ScenePresentationMixin: точки входа
|
||
# Публичные методы сценария:
|
||
# - ScenePresentationMixin.apply_scene_spec(...)
|
||
#
|
||
# B. ScenePresentationMixin: основной сценарий:
|
||
# ScenePresentationMixin.apply_scene_spec(...)
|
||
# Назначение: Применить ``SceneVisibilitySpec``, созданный политикой представления.
|
||
# Последовательность внутренних вызовов:
|
||
# -> ScenePresentationMixin._safe_call(...)
|
||
# -> ScenePresentationMixin._rack_filter_value(...)
|
||
#
|
||
# C. ScenePresentationMixin: вспомогательные расчёты:
|
||
# ScenePresentationMixin._safe_call(...)
|
||
# Назначение: выполняет шаг "safe call" в рамках текущего сценария модуля.
|
||
# ScenePresentationMixin._rack_filter_value(...)
|
||
# Назначение: выполняет шаг "rack filter value" в рамках текущего сценария модуля.
|
||
#
|
||
# 3) Важные ограничения и инварианты:
|
||
# - Модуль выполняется в составе ModelViewWidget и использует согласованные поля состояния self._... .
|
||
# - Межмодульная связность: только через фасад model_view; прямые обращения между zone, rack, shelf, cell запрещены.
|
||
# - Очистка состояния должна быть идемпотентной: повторный вызов не меняет корректное состояние в ошибочное.
|
||
#
|
||
# 4) Правило сопровождения:
|
||
# - Любое изменение сценария должно сопровождаться обновлением этого блока с сохранением фактического порядка вызовов.
|
||
# - При добавлении метода указывать его место в цепочке сценария (запуск, основной шаг, завершение, вспомогательная логика).
|