133 lines
5.6 KiB
Python
133 lines
5.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
# gui/components/_tree_node_building.py
|
|
"""Сервис построения узлов дерева и ленивой загрузки (композиция)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING, Dict, Any
|
|
|
|
from PySide6.QtCore import Qt
|
|
from PySide6.QtWidgets import QTreeWidgetItem
|
|
|
|
if TYPE_CHECKING:
|
|
from gui.components.topology_tree_widget import TopologyTreeWidget
|
|
|
|
|
|
class TreeNodeBuilder:
|
|
"""Создание элементов QTreeWidget и ленивая загрузка дочерних узлов."""
|
|
|
|
def __init__(self, host: "TopologyTreeWidget") -> None:
|
|
self._host = host
|
|
|
|
def load_root_nodes(self) -> None:
|
|
"""Загрузка корневых узлов (сайтов)."""
|
|
try:
|
|
root_nodes = self._host.data_loader('site', None)
|
|
for node_data in root_nodes:
|
|
item = self._create_tree_item(node_data)
|
|
self._host._tree.addTopLevelItem(item)
|
|
if node_data.has_children and not node_data.children_loaded:
|
|
stub = QTreeWidgetItem(["Загрузка..."])
|
|
stub.setData(0, Qt.UserRole, {"is_stub": True})
|
|
item.addChild(stub)
|
|
except Exception as e:
|
|
error_msg = f"Ошибка загрузки корневых узлов: {e}"
|
|
print(error_msg)
|
|
self._host.dataLoadError.emit(error_msg)
|
|
|
|
def _create_tree_item(self, node_data) -> QTreeWidgetItem:
|
|
"""Создание элемента дерева на основе данных узла."""
|
|
item = QTreeWidgetItem()
|
|
display_attrs = self._host.DISPLAY_ATTRIBUTES.get(node_data.node_type, [])
|
|
col_values = self._get_column_values(
|
|
node_data.display_data, display_attrs, node_data.node_type,
|
|
)
|
|
for i, value in enumerate(col_values):
|
|
if i < self._host._tree.columnCount():
|
|
item.setText(i, str(value))
|
|
item.setData(0, Qt.UserRole, {
|
|
'type': node_data.node_type,
|
|
'id': node_data.node_id,
|
|
'display_data': node_data.display_data,
|
|
'has_children': node_data.has_children,
|
|
'children_loaded': node_data.children_loaded,
|
|
'raw_data': node_data.raw_data,
|
|
})
|
|
item.setChildIndicatorPolicy(
|
|
QTreeWidgetItem.ShowIndicator if node_data.has_children
|
|
else QTreeWidgetItem.DontShowIndicator
|
|
)
|
|
return item
|
|
|
|
@staticmethod
|
|
def _get_column_values(
|
|
data: Dict[str, Any], attrs: list[str], node_type: str,
|
|
) -> list[str]:
|
|
"""Значения для колонок (только значения атрибутов, без ключей)."""
|
|
values = []
|
|
if attrs:
|
|
for attr in attrs:
|
|
if attr in data and data[attr]:
|
|
values.append(str(data[attr]))
|
|
break
|
|
else:
|
|
values.append("")
|
|
else:
|
|
values.append("")
|
|
if len(attrs) > 1:
|
|
other = [str(data[a]) for a in attrs[1:] if a in data and data[a]]
|
|
sep = " " if node_type == "shelf" else ", "
|
|
values.append(sep.join(other))
|
|
else:
|
|
values.append("")
|
|
return values
|
|
|
|
def load_children(self, parent_item: QTreeWidgetItem) -> None:
|
|
"""Ленивая загрузка дочерних элементов для узла."""
|
|
parent_data = parent_item.data(0, Qt.UserRole)
|
|
if not parent_data:
|
|
return
|
|
parent_type = parent_data['type']
|
|
parent_id = parent_data['id']
|
|
node_key = f"{parent_type}:{parent_id}"
|
|
if node_key in self._host._loading_nodes:
|
|
return
|
|
self._host._loading_nodes.add(node_key)
|
|
try:
|
|
if parent_item.childCount() == 1:
|
|
child = parent_item.child(0)
|
|
child_data = child.data(0, Qt.UserRole) if child else {}
|
|
if child_data and child_data.get('is_stub'):
|
|
parent_item.removeChild(child)
|
|
children_data = self._host.data_loader(
|
|
self._get_child_type(parent_type), parent_id,
|
|
)
|
|
for child_data in children_data:
|
|
child_item = self._create_tree_item(child_data)
|
|
parent_item.addChild(child_item)
|
|
if child_data.has_children and not child_data.children_loaded:
|
|
stub = QTreeWidgetItem(["Загрузка..."])
|
|
stub.setData(0, Qt.UserRole, {"is_stub": True})
|
|
child_item.addChild(stub)
|
|
parent_data['children_loaded'] = True
|
|
parent_item.setData(0, Qt.UserRole, parent_data)
|
|
self._host._tree.resizeColumnToContents(0)
|
|
except Exception as e:
|
|
msg = f"Ошибка загрузки дочерних элементов для {parent_type} {parent_id}: {e}"
|
|
print(msg)
|
|
self._host.dataLoadError.emit(msg)
|
|
err_item = QTreeWidgetItem(["Ошибка загрузки", str(e)[:50]])
|
|
err_item.setData(0, Qt.UserRole, {"is_error": True})
|
|
parent_item.addChild(err_item)
|
|
finally:
|
|
self._host._loading_nodes.remove(node_key)
|
|
|
|
@staticmethod
|
|
def _get_child_type(parent_type: str) -> str:
|
|
"""Тип дочерних элементов на основе типа родителя."""
|
|
hierarchy = {
|
|
'site': 'facility', 'facility': 'zone', 'zone': 'rack',
|
|
'rack': 'shelf', 'shelf': 'cell', 'cell': 'volume',
|
|
}
|
|
return hierarchy.get(parent_type, '')
|