221 lines
8.0 KiB
Python
221 lines
8.0 KiB
Python
import re
|
|
from PySide6.QtWidgets import (
|
|
QDialog, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QPushButton,
|
|
QLineEdit, QLabel, QHeaderView
|
|
)
|
|
from PySide6.QtCore import Qt
|
|
from setupVars import *
|
|
from scanVars import *
|
|
|
|
|
|
array_re = re.compile(r'^(\w+)\[(\d+)\]$')
|
|
|
|
class VariableSelectorDialog(QDialog):
|
|
def __init__(self, all_vars, structs, typedefs, parent=None):
|
|
super().__init__(parent)
|
|
self.setWindowTitle("Выбор переменных")
|
|
self.resize(600, 500)
|
|
self.selected_names = []
|
|
|
|
self.all_vars = all_vars
|
|
self.structs = structs
|
|
self.typedefs = typedefs
|
|
self.expanded_vars = []
|
|
self.var_map = {v['name']: v for v in all_vars}
|
|
|
|
self.search_input = QLineEdit()
|
|
self.search_input.setPlaceholderText("Поиск по имени переменной...")
|
|
self.search_input.textChanged.connect(self.filter_tree)
|
|
|
|
self.tree = QTreeWidget()
|
|
self.tree.setHeaderLabels(["Имя переменной", "Тип"])
|
|
self.tree.setSelectionMode(QTreeWidget.ExtendedSelection)
|
|
self.tree.setRootIsDecorated(True)
|
|
self.tree.setUniformRowHeights(True)
|
|
|
|
self.tree.setStyleSheet("""
|
|
QTreeWidget::item:selected {
|
|
background-color: #87CEFA;
|
|
color: black;
|
|
}
|
|
QTreeWidget::item:hover {
|
|
background-color: #D3D3D3;
|
|
}
|
|
""")
|
|
|
|
self.btn_add = QPushButton("Добавить выбранные")
|
|
self.btn_add.clicked.connect(self.on_add_clicked)
|
|
|
|
self.btn_delete = QPushButton("Удалить выбранные")
|
|
self.btn_delete.clicked.connect(self.on_delete_clicked)
|
|
|
|
layout = QVBoxLayout()
|
|
layout.addWidget(QLabel("Поиск:"))
|
|
layout.addWidget(self.search_input)
|
|
layout.addWidget(self.tree)
|
|
layout.addWidget(self.btn_add)
|
|
layout.addWidget(self.btn_delete) # Кнопка удаления
|
|
self.setLayout(layout)
|
|
|
|
self.populate_tree()
|
|
|
|
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'
|
|
|
|
item = QTreeWidgetItem([name, type_str])
|
|
item.setData(0, Qt.UserRole, name)
|
|
|
|
# Делаем bitfield-поля неактивными
|
|
if "(bitfield:" in type_str:
|
|
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)
|
|
|
|
for child in var.get('children', []):
|
|
self.add_tree_item_recursively(item, child)
|
|
|
|
|
|
def populate_tree(self):
|
|
self.tree.clear()
|
|
|
|
expanded_vars = expand_vars(self.all_vars, self.structs, self.typedefs)
|
|
|
|
for var in expanded_vars:
|
|
self.add_tree_item_recursively(None, var)
|
|
|
|
header = self.tree.header()
|
|
header.setSectionResizeMode(QHeaderView.Interactive) # вручную можно менять
|
|
self.tree.setColumnWidth(0, 400)
|
|
self.tree.resizeColumnToContents(1)
|
|
""" header.setSectionResizeMode(0, QHeaderView.Stretch)
|
|
header.setSectionResizeMode(1, QHeaderView.ResizeToContents) """
|
|
|
|
def filter_tree(self):
|
|
text = self.search_input.text().strip().lower()
|
|
path_parts = text.split('.') if text else []
|
|
|
|
def hide_all(item):
|
|
item.setHidden(True)
|
|
for i in range(item.childCount()):
|
|
hide_all(item.child(i))
|
|
|
|
def path_matches_search(name, search_parts):
|
|
name_parts = name.lower().split('.')
|
|
if len(name_parts) < len(search_parts):
|
|
return False
|
|
for sp, np in zip(search_parts, name_parts):
|
|
if not np.startswith(sp):
|
|
return False
|
|
return True
|
|
|
|
def show_matching_path(item, level=0):
|
|
name = item.text(0).lower()
|
|
# Проверяем соответствие до длины path_parts
|
|
if not path_parts:
|
|
matched = True
|
|
else:
|
|
matched = False
|
|
# Проверяем совпадение по пути
|
|
if path_matches_search(name, path_parts[:level+1]):
|
|
matched = True
|
|
|
|
item.setHidden(not matched)
|
|
|
|
# Раскрываем, если это не последний уровень поиска
|
|
if matched and level < len(path_parts) - 1:
|
|
item.setExpanded(True)
|
|
else:
|
|
item.setExpanded(False)
|
|
|
|
matched_any_child = False
|
|
for i in range(item.childCount()):
|
|
child = item.child(i)
|
|
if show_matching_path(child, level + 1):
|
|
matched_any_child = True
|
|
|
|
return matched or matched_any_child
|
|
|
|
for i in range(self.tree.topLevelItemCount()):
|
|
item = self.tree.topLevelItem(i)
|
|
hide_all(item)
|
|
show_matching_path(item, 0)
|
|
|
|
|
|
def on_add_clicked(self):
|
|
self.selected_names = []
|
|
|
|
for item in self.tree.selectedItems():
|
|
name = item.text(0) # имя переменной (в колонке 1)
|
|
type_str = item.text(1) # тип переменной (в колонке 2)
|
|
|
|
if not name or not type_str:
|
|
continue
|
|
|
|
self.selected_names.append((name, type_str))
|
|
|
|
if name in self.var_map:
|
|
# Если переменная уже есть, просто включаем её и показываем
|
|
var = self.var_map[name]
|
|
var['show_var'] = 'true'
|
|
var['enable'] = 'true'
|
|
else:
|
|
# Создаём новый элемент переменной
|
|
# Получаем родительские параметры
|
|
file_val = item.data(0, Qt.UserRole + 1)
|
|
extern_val = item.data(0, Qt.UserRole + 2)
|
|
static_val = item.data(0, Qt.UserRole + 3)
|
|
|
|
new_var = {
|
|
'name': name,
|
|
'type': type_str,
|
|
'show_var': 'true',
|
|
'enable': 'true',
|
|
'shortname': name,
|
|
'pt_type': '',
|
|
'iq_type': '',
|
|
'return_type': 'iq_none',
|
|
'file': file_val,
|
|
'extern': str(extern_val).lower() if extern_val else 'false',
|
|
'static': str(static_val).lower() if static_val else 'false',
|
|
}
|
|
|
|
# Добавляем в список переменных
|
|
self.all_vars.append(new_var)
|
|
self.var_map[name] = new_var # Чтобы в будущем не добавлялось повторно
|
|
|
|
self.accept()
|
|
|
|
def on_delete_clicked(self):
|
|
# Деактивируем (удаляем из видимых) выбранные переменные
|
|
for item in self.tree.selectedItems():
|
|
name = item.text(0)
|
|
if not name:
|
|
continue
|
|
if name in self.var_map:
|
|
var = self.var_map[name]
|
|
var['show_var'] = 'false'
|
|
var['enable'] = 'false'
|
|
self.accept()
|
|
|
|
|
|
def set_tool(self, item, text):
|
|
item.setToolTip(0, text)
|
|
item.setToolTip(1, text) |