356 lines
14 KiB
Python
356 lines
14 KiB
Python
import re
|
||
import xml.etree.ElementTree 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 VariableTable
|
||
import setupVars
|
||
import myXML
|
||
import time
|
||
import selectTable
|
||
|
||
|
||
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_add = QPushButton("Добавить выбранные")
|
||
self.btn_delete = QPushButton("Удалить выбранные")
|
||
|
||
# Создаем экземпляр вашего готового виджета
|
||
self.vars_widget = selectTable.VariableSelectWidget(self)
|
||
self.selected_vars_widget = selectTable.VariableSelectWidget(self)
|
||
|
||
|
||
# --- Лэйауты ---
|
||
main_layout = QVBoxLayout(self) # главный вертикальный layout окна
|
||
|
||
tables_layout = QHBoxLayout() # горизонтальный layout с таблицами и кнопками
|
||
|
||
# Левая таблица
|
||
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_add)
|
||
buttons_layout.addWidget(self.btn_delete)
|
||
main_layout.addLayout(buttons_layout)
|
||
|
||
# Важно, если окно — QDialog или QWidget, установи layout
|
||
self.setLayout(main_layout)
|
||
|
||
|
||
|
||
# Соединяем сигналы кнопок с методами диалога
|
||
self.btn_add.clicked.connect(self.on_add_clicked)
|
||
self.btn_delete.clicked.connect(self.on_delete_clicked)
|
||
|
||
# Соединяем чекбокс с методом виджета
|
||
self.autocomplete_checkbox.stateChanged.connect(self.vars_widget.set_autocomplete)
|
||
# Устанавливаем начальное состояние автодополнения в виджете
|
||
self.vars_widget.set_autocomplete(self.autocomplete_checkbox.isChecked())
|
||
self.selected_vars_widget.set_autocomplete(self.autocomplete_checkbox.isChecked())
|
||
|
||
# --- Код в конце __init__ ---
|
||
self.expanded_vars = setupVars.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'
|
||
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):
|
||
self.selected_vars, self.unselected_vars = setupVars.split_vars_by_show_flag(self.expanded_vars)
|
||
self.vars_widget.set_data(self.unselected_vars)
|
||
self.vars_widget.filter_tree()
|
||
self.selected_vars_widget.set_data(self.selected_vars)
|
||
self.selected_vars_widget.filter_tree()
|
||
|
||
|
||
|
||
def on_add_clicked(self):
|
||
# Получаем все переменные из правой таблицы (selected_vars_widget)
|
||
var_names = self.selected_vars_widget.get_all_var_names()
|
||
all_items = self.selected_vars_widget.get_all_items()
|
||
if not all_items:
|
||
return
|
||
|
||
def add_to_var_map_recursively(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': '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_to_var_map_recursively(item)
|
||
|
||
self.accept()
|
||
|
||
|
||
def on_delete_clicked(self):
|
||
# Получаем все элементы (QTreeWidgetItem) из правой таблицы
|
||
all_items = self.selected_vars_widget.get_all_items()
|
||
if not all_items:
|
||
return
|
||
|
||
affected_names = []
|
||
|
||
def disable_var_recursively(item):
|
||
name = item.text(0)
|
||
if name in self.var_map:
|
||
self.var_map[name]['show_var'] = 'false'
|
||
self.var_map[name]['enable'] = 'false'
|
||
affected_names.append(name)
|
||
|
||
# Рекурсивно отключаем детей
|
||
for i in range(item.childCount()):
|
||
child = item.child(i)
|
||
disable_var_recursively(child)
|
||
|
||
for item in all_items:
|
||
disable_var_recursively(item)
|
||
|
||
# Обновляем XML и таблицу
|
||
self.update_xml_vars(affected_names, 'false', 'false')
|
||
self.update_vars_widget()
|
||
|
||
|
||
def update_xml_vars(self, names, show, enable):
|
||
"""Обновляет флаги show_var и enable в XML файле, только если у переменной нет вложенных структур."""
|
||
if not self.xml_path:
|
||
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'):
|
||
if var_elem.attrib.get('name') in names:
|
||
# Проверяем наличие вложенных структур или объединений
|
||
has_nested_structs = any(
|
||
var_elem.find(tag) is not None for tag in ('struct', 'union')
|
||
)
|
||
if not has_nested_structs:
|
||
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', show)
|
||
set_text('enable', enable)
|
||
|
||
myXML.fwrite(root, self.xml_path)
|
||
|
||
|
||
def save_checkbox_state(self):
|
||
self.settings.setValue("autocomplete_enabled", self.autocomplete_checkbox.isChecked())
|
||
|
||
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
|
||
|
||
import xml.etree.ElementTree as ET
|
||
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())
|