|
|
|
|
@@ -5,6 +5,8 @@ from PySide2.QtWidgets import (
|
|
|
|
|
)
|
|
|
|
|
from PySide2.QtGui import QKeyEvent
|
|
|
|
|
from PySide2.QtCore import Qt, QStringListModel
|
|
|
|
|
import pickle
|
|
|
|
|
import time
|
|
|
|
|
|
|
|
|
|
# Вспомогательные функции, которые теперь будут использоваться виджетом
|
|
|
|
|
def split_path(path):
|
|
|
|
|
@@ -183,59 +185,30 @@ class VariableSelectWidget(QWidget):
|
|
|
|
|
|
|
|
|
|
def set_data(self, vars_list):
|
|
|
|
|
"""Основной метод для загрузки данных в виджет."""
|
|
|
|
|
self.expanded_vars = vars_list
|
|
|
|
|
self.expanded_vars = pickle.loads(pickle.dumps(vars_list, protocol=pickle.HIGHEST_PROTOCOL))
|
|
|
|
|
# self.build_completion_list() # Если нужна полная перестройка списка
|
|
|
|
|
self.populate_tree()
|
|
|
|
|
|
|
|
|
|
def _get_internal_selected_items(self):
|
|
|
|
|
"""Возвращает выделенные элементы и всех их потомков."""
|
|
|
|
|
selected = self.tree.selectedItems()
|
|
|
|
|
all_items = []
|
|
|
|
|
|
|
|
|
|
def collect_children(item):
|
|
|
|
|
items = [item]
|
|
|
|
|
for i in range(item.childCount()):
|
|
|
|
|
child = item.child(i)
|
|
|
|
|
items.extend(collect_children(child))
|
|
|
|
|
return items
|
|
|
|
|
|
|
|
|
|
for item in selected:
|
|
|
|
|
all_items.extend(collect_children(item))
|
|
|
|
|
|
|
|
|
|
return all_items
|
|
|
|
|
|
|
|
|
|
def _get_internal_selected_var_names(self):
|
|
|
|
|
"""Возвращает имена выделенных переменных."""
|
|
|
|
|
return [item.text(0) for item in self._get_internal_selected_items() if item.text(0)]
|
|
|
|
|
|
|
|
|
|
def get_selected_items(self):
|
|
|
|
|
"""Возвращает только конечные (leaf) выделенные элементы, исключая bitfield."""
|
|
|
|
|
selected = self.tree.selectedItems()
|
|
|
|
|
leaf_items = []
|
|
|
|
|
for item in selected:
|
|
|
|
|
# Проверка: если нет выбранных/видимых детей — это лист
|
|
|
|
|
if all(item.child(i).isHidden() or not item.child(i).isSelected() for i in range(item.childCount())):
|
|
|
|
|
item_type = item.data(0, Qt.UserRole)
|
|
|
|
|
if item_type and 'bitfield' in str(item_type).lower():
|
|
|
|
|
continue # Пропускаем битовые поля
|
|
|
|
|
leaf_items.append(item)
|
|
|
|
|
return leaf_items
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_selected_var_names(self):
|
|
|
|
|
"""Возвращает имена только конечных (leaf) переменных из выделенных."""
|
|
|
|
|
return [item.text(0) for item in self.get_selected_items() if item.text(0)]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def populate_tree(self, vars_list=None):
|
|
|
|
|
if vars_list is None:
|
|
|
|
|
vars_list = self.expanded_vars
|
|
|
|
|
self.tree.setUpdatesEnabled(False)
|
|
|
|
|
self.tree.blockSignals(True)
|
|
|
|
|
self.tree.clear()
|
|
|
|
|
self.node_index.clear()
|
|
|
|
|
start_add = time.perf_counter()
|
|
|
|
|
stats = {'count': 0, 'time': 0.0}
|
|
|
|
|
for var in vars_list:
|
|
|
|
|
self.add_tree_item_recursively(None, var)
|
|
|
|
|
self.add_tree_item_recursively(None, var, stats)
|
|
|
|
|
end_add = time.perf_counter()
|
|
|
|
|
|
|
|
|
|
print(f" add items: {end_add - start_add:.6f} s")
|
|
|
|
|
print(f" └ recursive only: {stats['time']:.6f} s")
|
|
|
|
|
print(f" └ total items: {stats['count']} шт")
|
|
|
|
|
|
|
|
|
|
self.tree.setUpdatesEnabled(True)
|
|
|
|
|
self.tree.blockSignals(False)
|
|
|
|
|
header = self.tree.header()
|
|
|
|
|
header.setSectionResizeMode(QHeaderView.Interactive) # вручную можно менять
|
|
|
|
|
self.tree.setColumnWidth(0, 400)
|
|
|
|
|
@@ -253,41 +226,42 @@ class VariableSelectWidget(QWidget):
|
|
|
|
|
return fullname
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_tree_item_recursively(self, parent, var):
|
|
|
|
|
"""
|
|
|
|
|
Рекурсивно добавляет переменную и её дочерние поля в дерево.
|
|
|
|
|
Если parent == None, добавляет на верхний уровень.
|
|
|
|
|
"""
|
|
|
|
|
name = var['name']
|
|
|
|
|
type_str = var.get('type', '')
|
|
|
|
|
show_var = var.get('show_var', 'false') == 'true'
|
|
|
|
|
def add_tree_item_recursively(self, parent, var, stats=None, parent_path=""):
|
|
|
|
|
if stats is None:
|
|
|
|
|
stats = {'count': 0, 'time': 0.0}
|
|
|
|
|
|
|
|
|
|
start = time.perf_counter()
|
|
|
|
|
|
|
|
|
|
name = var['name']
|
|
|
|
|
full_name = f"{parent_path}.{name}" if parent_path else name
|
|
|
|
|
full_name = full_name.replace('->', '.') # если нужно
|
|
|
|
|
|
|
|
|
|
type_str = var.get('type', '')
|
|
|
|
|
item = QTreeWidgetItem([name, type_str])
|
|
|
|
|
item.setData(0, Qt.UserRole, name)
|
|
|
|
|
full_name = self.get_full_item_name(item)
|
|
|
|
|
self.node_index[full_name.lower()] = item
|
|
|
|
|
|
|
|
|
|
# Делаем bitfield-поля неактивными
|
|
|
|
|
if "(bitfield:" in type_str:
|
|
|
|
|
item.setDisabled(True)
|
|
|
|
|
item.setDisabled(True)
|
|
|
|
|
self.set_tool(item, "Битовые поля недоступны для выбора")
|
|
|
|
|
|
|
|
|
|
for i, attr in enumerate(['file', 'extern', 'static']):
|
|
|
|
|
item.setData(0, Qt.UserRole + 1 + i, var.get(attr))
|
|
|
|
|
|
|
|
|
|
if show_var:
|
|
|
|
|
item.setForeground(0, Qt.gray)
|
|
|
|
|
item.setForeground(1, Qt.gray)
|
|
|
|
|
self.set_tool(item, "Уже добавлена")
|
|
|
|
|
|
|
|
|
|
if parent is None:
|
|
|
|
|
self.tree.addTopLevelItem(item)
|
|
|
|
|
else:
|
|
|
|
|
parent.addChild(item)
|
|
|
|
|
|
|
|
|
|
stats['count'] += 1
|
|
|
|
|
|
|
|
|
|
for child in var.get('children', []):
|
|
|
|
|
self.add_tree_item_recursively(item, child)
|
|
|
|
|
|
|
|
|
|
self.add_tree_item_recursively(item, child, stats, parent_path=full_name)
|
|
|
|
|
|
|
|
|
|
end = time.perf_counter()
|
|
|
|
|
stats['time'] += end - start
|
|
|
|
|
return stats
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def filter_tree(self):
|
|
|
|
|
text = self.search_input.text().strip().lower()
|
|
|
|
|
@@ -309,8 +283,6 @@ class VariableSelectWidget(QWidget):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def find_node_by_path(self, root_vars, path_list):
|
|
|
|
|
current_level = root_vars
|
|
|
|
|
node = None
|
|
|
|
|
@@ -574,3 +546,45 @@ class VariableSelectWidget(QWidget):
|
|
|
|
|
def get_all_var_names(self):
|
|
|
|
|
"""Возвращает имена всех конечных (leaf) переменных, исключая битовые поля и группы."""
|
|
|
|
|
return [item.text(0) for item in self.get_all_items() if item.text(0)]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _get_internal_selected_items(self):
|
|
|
|
|
"""Возвращает выделенные элементы и всех их потомков."""
|
|
|
|
|
selected = self.tree.selectedItems()
|
|
|
|
|
all_items = []
|
|
|
|
|
|
|
|
|
|
def collect_children(item):
|
|
|
|
|
items = [item]
|
|
|
|
|
for i in range(item.childCount()):
|
|
|
|
|
child = item.child(i)
|
|
|
|
|
items.extend(collect_children(child))
|
|
|
|
|
return items
|
|
|
|
|
|
|
|
|
|
for item in selected:
|
|
|
|
|
all_items.extend(collect_children(item))
|
|
|
|
|
|
|
|
|
|
return all_items
|
|
|
|
|
|
|
|
|
|
def _get_internal_selected_var_names(self):
|
|
|
|
|
"""Возвращает имена выделенных переменных."""
|
|
|
|
|
return [item.text(0) for item in self._get_internal_selected_items() if item.text(0)]
|
|
|
|
|
|
|
|
|
|
def get_selected_items(self):
|
|
|
|
|
"""Возвращает только конечные (leaf) выделенные элементы, исключая bitfield."""
|
|
|
|
|
selected = self.tree.selectedItems()
|
|
|
|
|
leaf_items = []
|
|
|
|
|
for item in selected:
|
|
|
|
|
# Проверка: если нет выбранных/видимых детей — это лист
|
|
|
|
|
if all(item.child(i).isHidden() or not item.child(i).isSelected() for i in range(item.childCount())):
|
|
|
|
|
item_type = item.data(0, Qt.UserRole)
|
|
|
|
|
if item_type and 'bitfield' in str(item_type).lower():
|
|
|
|
|
continue # Пропускаем битовые поля
|
|
|
|
|
leaf_items.append(item)
|
|
|
|
|
return leaf_items
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_selected_var_names(self):
|
|
|
|
|
"""Возвращает имена только конечных (leaf) переменных из выделенных."""
|
|
|
|
|
return [item.text(0) for item in self.get_selected_items() if item.text(0)]
|
|
|
|
|
|
|
|
|
|
|