debugVarTool/Src/var_selector_window.py
Razvalyaev 96496a0256 все неплохо работает.
сейв перед попыткой улучшить lowlevel debug
2025-07-21 13:40:52 +03:00

392 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import re
import lxml.etree as ET
from PySide2.QtWidgets import (
QDialog, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QPushButton,
QLineEdit, QLabel, QHeaderView, QCompleter, QCheckBox, QHBoxLayout, QSizePolicy
)
from PySide2.QtGui import QKeySequence, QKeyEvent
from PySide2.QtCore import Qt, QStringListModel, QSettings
import var_table
import var_setup
import myXML
import time
import var_selector_table
array_re = re.compile(r'^(\w+)\[(\d+)\]$')
class VariableSelectorDialog(QDialog):
def __init__(self, table, all_vars, structs, typedefs, xml_path=None, parent=None):
super().__init__(parent)
self.setWindowTitle("Выбор переменных")
self.setAttribute(Qt.WA_DeleteOnClose)
self.resize(1200, 500)
self.selected_names = []
self._bckspc_pressed = False # флаг подавления добавления разделителя
self.table = table
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.node_index = {}
self.xml_path = xml_path # сохраняем путь к xml
self.manual_completion_active = False
# --- Добавляем чекбокс для автодополнения ---
self.autocomplete_checkbox = QCheckBox("Включить автодополнение")
self.autocomplete_checkbox.setChecked(True)
# Инициализируем QSettings с именем организации и приложения
self.settings = QSettings("SET", "DebugVarEdit_VarsSelector")
# Восстанавливаем сохранённое состояние чекбокса, если есть
checked = self.settings.value("autocomplete_enabled", True, type=bool)
self.autocomplete_checkbox.setChecked(checked)
# При изменении состояния чекбокса сохраняем его
self.autocomplete_checkbox.stateChanged.connect(self.save_checkbox_state)
# Кнопки между таблицами
self.btn_right = QPushButton(">")
self.btn_right.clicked.connect(self.on_move_right)
self.btn_left = QPushButton("<")
self.btn_left.clicked.connect(self.on_move_left)
# Создаем кнопки, они остаются в диалоге
self.btn_accept = QPushButton("Применить")
# Создаем экземпляр вашего готового виджета
self.vars_widget = var_selector_table.VariableSelectWidget(self)
self.vars_widget.tree.itemDoubleClicked.connect(self.on_left_tree_double_click)
self.vars_widget.setObjectName("LeftTable")
self.selected_vars_widget = var_selector_table.VariableSelectWidget(self)
self.selected_vars_widget.tree.itemDoubleClicked.connect(self.on_rigth_tree_double_click)
self.selected_vars_widget.setObjectName("RightTable")
# Подписи над таблицами
label_all = QLabel("Все переменные")
label_all.setStyleSheet("font-weight: bold; font-size: 14px;")
label_selected = QLabel("Выбранные переменные")
label_selected.setStyleSheet("font-weight: bold; font-size: 14px;")
# --- Лэйауты ---
main_layout = QVBoxLayout(self) # главный вертикальный layout окна
# Чекбокс автодополнения — первый в главном layout
main_layout.addWidget(self.autocomplete_checkbox)
# Подписи над таблицами
labels_layout = QHBoxLayout()
labels_layout.addWidget(label_all)
labels_layout.addStretch()
labels_layout.addWidget(label_selected)
main_layout.addLayout(labels_layout)
# Горизонтальный layout с таблицами и кнопками
tables_layout = QHBoxLayout()
# Левая таблица
self.vars_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
tables_layout.addWidget(self.vars_widget)
# Кнопки ">" и "<" между таблицами
middle_buttons_layout = QVBoxLayout()
middle_buttons_layout.addStretch()
middle_buttons_layout.addWidget(self.btn_right)
middle_buttons_layout.addWidget(self.btn_left)
middle_buttons_layout.addStretch()
tables_layout.addLayout(middle_buttons_layout)
# Правая таблица
self.selected_vars_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
tables_layout.addWidget(self.selected_vars_widget)
# Добавляем горизонтальный layout с таблицами в главный вертикальный
main_layout.addLayout(tables_layout)
# Кнопки "Добавить выбранные" и "Удалить выбранные" под таблицами
buttons_layout = QVBoxLayout()
buttons_layout.addWidget(self.btn_accept)
main_layout.addLayout(buttons_layout)
# Важно, если окно — QDialog или QWidget, установи layout
self.setLayout(main_layout)
# Соединяем сигналы кнопок с методами диалога
self.btn_accept.clicked.connect(self.on_apply_clicked)
# Соединяем чекбокс с методом виджета
self.autocomplete_checkbox.stateChanged.connect(self.set_autocomplete_tables)
# Устанавливаем начальное состояние автодополнения в виджете
self.vars_widget.set_autocomplete(self.autocomplete_checkbox.isChecked())
self.selected_vars_widget.set_autocomplete(self.autocomplete_checkbox.isChecked())
# --- Код в конце __init__ ---
self.expanded_vars = var_setup.expand_vars(self.all_vars, self.structs, self.typedefs)
self.update_vars_widget()
def on_move_right(self):
# Устанавливаем show_var=True для всех выбранных переменных из ЛЕВОЙ таблицы
selected = self.vars_widget._get_internal_selected_var_names()
if not selected:
return
def mark_selected_show_var(data):
for var in data:
if var['name'] in selected:
var['show_var'] = 'true'
var['enable'] = 'true'
if 'children' in var:
mark_selected_show_var(var['children'])
mark_selected_show_var(self.expanded_vars)
self.update_vars_widget()
def on_move_left(self):
# Сбрасываем show_var=False для всех выбранных переменных из ПРАВОЙ таблицы
selected = self.selected_vars_widget._get_internal_selected_var_names()
if not selected:
return
def mark_selected_hide_var(data):
for var in data:
if var['name'] in selected:
var['show_var'] = 'false'
if 'children' in var:
mark_selected_hide_var(var['children'])
mark_selected_hide_var(self.expanded_vars)
self.update_vars_widget()
def update_vars_widget(self):
t_start = time.perf_counter()
t1 = time.perf_counter()
self.selected_vars, self.unselected_vars = var_setup.split_vars_by_show_flag(self.expanded_vars)
t2 = time.perf_counter()
self.vars_widget.set_data(self.unselected_vars)
t3 = time.perf_counter()
self.vars_widget.filter_tree()
t4 = time.perf_counter()
self.selected_vars_widget.set_data(self.selected_vars)
t5 = time.perf_counter()
self.selected_vars_widget.filter_tree()
def on_apply_clicked(self):
# Получаем имена всех переменных из правой таблицы (selected_vars_widget)
right_var_names = set(self.selected_vars_widget.get_all_var_names())
all_items = self.selected_vars_widget.get_all_items()
if not all_items:
return
# Устанавливаем show_var=true и enable=true для переменных из правой таблицы
def add_or_update_var(item):
name = item.text(0)
type_str = item.text(1)
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': 't_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
for item in all_items:
add_or_update_var(item)
# Сбрасываем show_var и enable у всех переменных, которых нет в правой таблице
for var in self.all_vars:
if var['name'] not in right_var_names:
var['show_var'] = 'false'
var['enable'] = 'false'
# Обновляем expanded_vars чтобы отразить новые show_var и enable
def update_expanded_vars(data):
for v in data:
name = v['name']
if name in self.var_map:
v['show_var'] = self.var_map[name]['show_var']
v['enable'] = self.var_map[name]['enable']
if 'children' in v:
update_expanded_vars(v['children'])
update_expanded_vars(self.expanded_vars)
# Обновляем отображение в виджетах
self.update_vars_widget()
# Закрываем диалог
self.accept()
# Обнови on_left_tree_double_click:
def on_left_tree_double_click(self, item, column):
selected_names = [item.text(0)]
if not selected_names:
return
def mark_selected_show_var(data):
for var in data:
if var['name'] in selected_names:
var['show_var'] = 'true'
var['enable'] = 'true'
if 'children' in var:
mark_selected_show_var(var['children'])
mark_selected_show_var(self.expanded_vars)
self.update_vars_widget()
# Добавь обработчик двойного клика справа (если нужно):
def on_rigth_tree_double_click(self, item, column):
selected_names = [item.text(0)]
if not selected_names:
return
def mark_selected_hide_var(data):
for var in data:
if var['name'] in selected_names:
var['show_var'] = 'false'
if 'children' in var:
mark_selected_hide_var(var['children'])
mark_selected_hide_var(self.expanded_vars)
self.update_vars_widget()
def keyPressEvent(self, event):
if event.key() == Qt.Key_Delete:
self.delete_selected_vars()
else:
super().keyPressEvent(event)
def delete_selected_vars(self):
selected_names = self._get_selected_var_names()
if not selected_names:
print("nothing selected")
return
# Обновляем var_map и all_vars
for name in selected_names:
if name in self.var_map:
self.var_map[name]['show_var'] = 'false'
self.var_map[name]['enable'] = 'false'
for v in self.all_vars:
if v['name'] == name:
v['show_var'] = 'false'
v['enable'] = 'false'
break
# Проверка пути к XML
if not hasattr(self, 'xml_path') or not self.xml_path:
from PySide2.QtWidgets import QMessageBox
#QMessageBox.warning(self, "Ошибка", "Путь к XML не задан, невозможно обновить переменные.")
return
root, tree = myXML.safe_parse_xml(self.xml_path)
if root is None:
return
vars_section = root.find('variables')
if vars_section is None:
return
for var_elem in vars_section.findall('var'):
name = var_elem.attrib.get('name')
if name in selected_names:
def set_text(tag, value):
el = var_elem.find(tag)
if el is None:
el = ET.SubElement(var_elem, tag)
el.text = value
set_text('show_var', 'false')
set_text('enable', 'false')
myXML.fwrite(root, self.xml_path)
self.table.populate(self.all_vars, self.structs, None)
# Проверка пути к XML
if not hasattr(self, 'xml_path') or not self.xml_path:
from PySide2.QtWidgets import QMessageBox
QMessageBox.warning(self, "Ошибка", "Путь к XML не задан, невозможно удалить переменные.")
return
root, tree = myXML.safe_parse_xml(self.xml_path)
if root is None:
return
vars_section = root.find('variables')
if vars_section is None:
return
removed_any = False
for var_elem in list(vars_section.findall('var')):
name = var_elem.attrib.get('name')
if name in selected_names:
vars_section.remove(var_elem)
removed_any = True
self.var_map.pop(name, None)
# Удаляем из all_vars (глобально)
self.all_vars[:] = [v for v in self.all_vars if v['name'] not in selected_names]
# Удаляем из expanded_vars (тоже глобально)
def filter_out_selected(vars_list):
filtered = []
for v in vars_list:
if v['name'] not in selected_names:
# Рекурсивно фильтруем детей, если есть
if 'children' in v:
v = v.copy()
v['children'] = filter_out_selected(v['children'])
filtered.append(v)
return filtered
self.expanded_vars[:] = filter_out_selected(self.expanded_vars)
if removed_any:
myXML.fwrite(root, self.xml_path)
self.update_vars_widget()
def _get_selected_var_names(self):
focused = self.focusWidget()
if focused and focused is self.vars_widget.tree:
return self.vars_widget.get_selected_var_names()
elif focused and focused is self.selected_vars_widget.tree:
return self.selected_vars_widget.get_selected_var_names()
else:
return []
def save_checkbox_state(self):
self.settings.setValue("autocomplete_enabled", self.autocomplete_checkbox.isChecked())
def set_autocomplete_tables(self, state):
self.vars_widget.set_autocomplete(state)
self.selected_vars_widget.set_autocomplete(state)