ну вроде работает, но опять тормозит
This commit is contained in:
@@ -413,16 +413,18 @@ class VarEditor(QWidget):
|
||||
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Ошибка", f"Не удалось загрузить переменные:\n{e}")
|
||||
|
||||
|
||||
def delete_selected_rows(self):
|
||||
selected_rows = sorted(set(index.row() for index in self.table.selectedIndexes()), reverse=True)
|
||||
if not selected_rows:
|
||||
# Получаем имена всех выбранных переменных из первого столбца
|
||||
selected_names = self.table.get_selected_var_names()
|
||||
|
||||
if not selected_names:
|
||||
return
|
||||
|
||||
for row in selected_rows:
|
||||
if 0 <= row < len(self.vars_list):
|
||||
# Меняем флаг show_var для переменной с этим индексом
|
||||
self.vars_list[row]['show_var'] = 'false'
|
||||
# Меняем флаг show_var по имени
|
||||
for var in self.vars_list:
|
||||
if var.get('name') in selected_names:
|
||||
var['show_var'] = 'false'
|
||||
|
||||
self.table.populate(self.vars_list, self.structs, self.write_to_xml)
|
||||
self.write_to_xml()
|
||||
@@ -517,6 +519,11 @@ class VarEditor(QWidget):
|
||||
el = ET.SubElement(parent, tag)
|
||||
el.text = str(text)
|
||||
|
||||
pt_type_val = v_table['pt_type'] if v_table and 'pt_type' in v_table else v.get('pt_type', '')
|
||||
|
||||
if 'arr' in pt_type_val or 'struct' in pt_type_val or 'union' in pt_type_val:
|
||||
continue
|
||||
|
||||
show_var_val = str(v.get('show_var', 'false')).lower()
|
||||
enable_val = str(v_table['enable'] if v_table and 'enable' in v_table else v.get('enable', 'false')).lower()
|
||||
|
||||
@@ -525,7 +532,6 @@ class VarEditor(QWidget):
|
||||
|
||||
# Тут подтягиваем из таблицы, если есть, иначе из v
|
||||
shortname_val = v_table['shortname'] if v_table and 'shortname' in v_table else v.get('shortname', '')
|
||||
pt_type_val = v_table['pt_type'] if v_table and 'pt_type' in v_table else v.get('pt_type', '')
|
||||
iq_type_val = v_table['iq_type'] if v_table and 'iq_type' in v_table else v.get('iq_type', '')
|
||||
ret_type_val = v_table['return_type'] if v_table and 'return_type' in v_table else v.get('return_type', '')
|
||||
|
||||
|
||||
@@ -107,14 +107,11 @@ class VariableSelectorDialog(QDialog):
|
||||
|
||||
# --- Код в конце __init__ ---
|
||||
self.expanded_vars = setupVars.expand_vars(self.all_vars, self.structs, self.typedefs)
|
||||
self.selected_vars = setupVars.filter_selected_vars(self.expanded_vars)
|
||||
# Передаем данные в виджет
|
||||
self.vars_widget.set_data(self.expanded_vars)
|
||||
self.selected_vars_widget.set_data(self.selected_vars)
|
||||
self.update_vars_widget()
|
||||
|
||||
def on_move_right(self):
|
||||
# Устанавливаем show_var=True для всех выбранных переменных из ЛЕВОЙ таблицы
|
||||
selected = self.vars_widget.get_selected_var_names()
|
||||
selected = self.vars_widget._get_internal_selected_var_names()
|
||||
if not selected:
|
||||
return
|
||||
|
||||
@@ -126,11 +123,11 @@ class VariableSelectorDialog(QDialog):
|
||||
mark_selected_show_var(var['children'])
|
||||
mark_selected_show_var(self.expanded_vars)
|
||||
|
||||
self.update_selected_vars_widget()
|
||||
self.update_vars_widget()
|
||||
|
||||
def on_move_left(self):
|
||||
# Сбрасываем show_var=False для всех выбранных переменных из ПРАВОЙ таблицы
|
||||
selected = self.selected_vars_widget.get_selected_var_names()
|
||||
selected = self.selected_vars_widget._get_internal_selected_var_names()
|
||||
if not selected:
|
||||
return
|
||||
|
||||
@@ -142,21 +139,25 @@ class VariableSelectorDialog(QDialog):
|
||||
mark_selected_hide_var(var['children'])
|
||||
mark_selected_hide_var(self.expanded_vars)
|
||||
|
||||
self.update_selected_vars_widget()
|
||||
self.update_vars_widget()
|
||||
|
||||
def update_selected_vars_widget(self):
|
||||
self.selected_vars = setupVars.filter_selected_vars(self.expanded_vars)
|
||||
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
|
||||
|
||||
for item in all_items:
|
||||
def add_to_var_map_recursively(item):
|
||||
name = item.text(0)
|
||||
type_str = item.text(1)
|
||||
|
||||
@@ -178,41 +179,66 @@ class VariableSelectorDialog(QDialog):
|
||||
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):
|
||||
# Получаем все имена переменных из правой таблицы
|
||||
all_names = self.selected_vars_widget.get_all_var_names()
|
||||
if not all_names:
|
||||
# Получаем все элементы (QTreeWidgetItem) из правой таблицы
|
||||
all_items = self.selected_vars_widget.get_all_items()
|
||||
if not all_items:
|
||||
return
|
||||
|
||||
for name in all_names:
|
||||
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)
|
||||
|
||||
self.update_xml_vars(all_names, 'false', 'false')
|
||||
self.update_selected_vars_widget()
|
||||
# Рекурсивно отключаем детей
|
||||
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 файле."""
|
||||
"""Обновляет флаги show_var и enable в XML файле, только если у переменной нет вложенных структур."""
|
||||
if not self.xml_path:
|
||||
return
|
||||
root, tree = myXML.safe_parse_xml(self.xml_path)
|
||||
if root is None: return
|
||||
if root is None:
|
||||
return
|
||||
vars_section = root.find('variables')
|
||||
if vars_section is None: return
|
||||
if vars_section is None:
|
||||
return
|
||||
|
||||
for var_elem in vars_section.findall('var'):
|
||||
if var_elem.attrib.get('name') in 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', show)
|
||||
set_text('enable', enable)
|
||||
# Проверяем наличие вложенных структур или объединений
|
||||
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)
|
||||
|
||||
|
||||
@@ -314,12 +340,16 @@ class VariableSelectorDialog(QDialog):
|
||||
if removed_any:
|
||||
myXML.fwrite(root, self.xml_path)
|
||||
|
||||
self.filter_tree()
|
||||
self.update_vars_widget()
|
||||
|
||||
def _get_selected_var_names(self):
|
||||
self.tree.setFocus()
|
||||
return [item.text(0) for item in self.tree.selectedItems() if item.text(0)]
|
||||
|
||||
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())
|
||||
|
||||
@@ -268,4 +268,17 @@ class VariableTableWidget(QTableWidget):
|
||||
elif widget is not None:
|
||||
# Надёжная подсветка: через styleSheet
|
||||
widget.setStyleSheet(css_color)
|
||||
widget.setToolTip(tooltip if color else "")
|
||||
widget.setToolTip(tooltip if color else "")
|
||||
|
||||
def get_selected_var_names(self):
|
||||
selected_indexes = self.selectedIndexes()
|
||||
selected_rows = set(index.row() for index in selected_indexes)
|
||||
names = []
|
||||
|
||||
for row in selected_rows:
|
||||
name_widget = self.cellWidget(row, rows.name)
|
||||
if name_widget:
|
||||
name = name_widget.text()
|
||||
if name:
|
||||
names.append(name)
|
||||
return names
|
||||
|
||||
@@ -187,13 +187,45 @@ class VariableSelectWidget(QWidget):
|
||||
# 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):
|
||||
"""Возвращает выделенные элементы QTreeWidget."""
|
||||
return self.tree.selectedItems()
|
||||
"""Возвращает только конечные (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):
|
||||
"""Возвращает имена выделенных переменных."""
|
||||
return [item.text(0) for item in self.tree.selectedItems() if item.text(0)]
|
||||
"""Возвращает имена только конечных (leaf) переменных из выделенных."""
|
||||
return [item.text(0) for item in self.get_selected_items() if item.text(0)]
|
||||
|
||||
|
||||
def populate_tree(self, vars_list=None):
|
||||
@@ -220,16 +252,7 @@ class VariableSelectWidget(QWidget):
|
||||
fullname = fullname.replace('->', '.')
|
||||
return fullname
|
||||
|
||||
|
||||
def get_selected_vars(self):
|
||||
selected = self.tree.selectedItems()
|
||||
result = []
|
||||
for item in selected:
|
||||
var = item.data(0, Qt.UserRole)
|
||||
if var:
|
||||
result.append(var)
|
||||
return result
|
||||
|
||||
|
||||
def add_tree_item_recursively(self, parent, var):
|
||||
"""
|
||||
Рекурсивно добавляет переменную и её дочерние поля в дерево.
|
||||
@@ -519,7 +542,35 @@ class VariableSelectWidget(QWidget):
|
||||
item.setToolTip(1, text)
|
||||
|
||||
def get_all_items(self):
|
||||
return [self.tree.topLevelItem(i) for i in range(self.tree.topLevelItemCount())]
|
||||
|
||||
"""Возвращает все конечные (leaf) элементы, исключая битовые поля и элементы с детьми."""
|
||||
def collect_leaf_items(parent):
|
||||
leaf_items = []
|
||||
for i in range(parent.childCount()):
|
||||
child = parent.child(i)
|
||||
if child.isHidden():
|
||||
continue
|
||||
if child.childCount() == 0:
|
||||
item_type = child.text(1)
|
||||
if item_type and 'bitfield' in str(item_type).lower():
|
||||
continue
|
||||
leaf_items.append(child)
|
||||
else:
|
||||
leaf_items.extend(collect_leaf_items(child))
|
||||
return leaf_items
|
||||
|
||||
all_leaf_items = []
|
||||
for i in range(self.tree.topLevelItemCount()):
|
||||
top = self.tree.topLevelItem(i)
|
||||
if top.childCount() == 0:
|
||||
item_type = top.text(1)
|
||||
if item_type and 'bitfield' in str(item_type).lower():
|
||||
continue
|
||||
all_leaf_items.append(top)
|
||||
else:
|
||||
all_leaf_items.extend(collect_leaf_items(top))
|
||||
return all_leaf_items
|
||||
|
||||
|
||||
def get_all_var_names(self):
|
||||
return [self.tree.topLevelItem(i).text(0) for i in range(self.tree.topLevelItemCount())]
|
||||
"""Возвращает имена всех конечных (leaf) переменных, исключая битовые поля и группы."""
|
||||
return [item.text(0) for item in self.get_all_items() if item.text(0)]
|
||||
|
||||
187
Src/setupVars.py
187
Src/setupVars.py
@@ -7,6 +7,56 @@ from enum import IntEnum
|
||||
import scanVars
|
||||
import myXML
|
||||
|
||||
# Вспомогательные функции, которые теперь будут использоваться виджетом
|
||||
def split_path(path):
|
||||
"""
|
||||
Разбивает путь на компоненты:
|
||||
- 'foo[2].bar[1]->baz' → ['foo', '[2]', 'bar', '[1]', 'baz']
|
||||
Если видит '-' в конце строки (без '>' после) — обрезает этот '-'
|
||||
"""
|
||||
tokens = []
|
||||
token = ''
|
||||
i = 0
|
||||
length = len(path)
|
||||
while i < length:
|
||||
c = path[i]
|
||||
# Разделители: '->' и '.'
|
||||
if c == '-' and i + 1 < length and path[i:i+2] == '->':
|
||||
if token:
|
||||
tokens.append(token)
|
||||
token = ''
|
||||
i += 2
|
||||
continue
|
||||
elif c == '-' and i == length - 1:
|
||||
# '-' на конце строки без '>' после — просто пропускаем его
|
||||
i += 1
|
||||
continue
|
||||
elif c == '.':
|
||||
if token:
|
||||
tokens.append(token)
|
||||
token = ''
|
||||
i += 1
|
||||
continue
|
||||
elif c == '[':
|
||||
if token:
|
||||
tokens.append(token)
|
||||
token = ''
|
||||
idx = ''
|
||||
while i < length and path[i] != ']':
|
||||
idx += path[i]
|
||||
i += 1
|
||||
if i < length and path[i] == ']':
|
||||
idx += ']'
|
||||
i += 1
|
||||
tokens.append(idx)
|
||||
continue
|
||||
else:
|
||||
token += c
|
||||
i += 1
|
||||
if token:
|
||||
tokens.append(token)
|
||||
return tokens
|
||||
|
||||
|
||||
def make_absolute_path(path, base_path):
|
||||
if not os.path.isabs(path) and os.path.isdir(base_path):
|
||||
@@ -405,19 +455,132 @@ def expand_vars(vars_list, structs, typedefs):
|
||||
|
||||
return expanded
|
||||
|
||||
def filter_selected_vars(expanded_vars):
|
||||
|
||||
def build_full_names(parts, full_name):
|
||||
"""
|
||||
Восстанавливает вложенные полные имена из списка частей,
|
||||
ориентируясь на оригинальное полное имя (с '.', '->' и индексами).
|
||||
|
||||
Пример:
|
||||
parts = ['arr', '[0]', '[1]', 'ptr', 'val']
|
||||
full_name = 'arr[0][1].ptr->val'
|
||||
|
||||
→ [
|
||||
'arr',
|
||||
'arr[0]',
|
||||
'arr[0][1]',
|
||||
'arr[0][1].ptr',
|
||||
'arr[0][1].ptr->val'
|
||||
]
|
||||
"""
|
||||
names = []
|
||||
acc = ''
|
||||
idx = 0
|
||||
for part in parts:
|
||||
pos = full_name.find(part, idx)
|
||||
if pos == -1:
|
||||
acc += part
|
||||
else:
|
||||
acc = full_name[:pos + len(part)]
|
||||
idx = pos + len(part)
|
||||
names.append(acc)
|
||||
return names
|
||||
|
||||
def find_var_by_name(tree, name):
|
||||
for var in tree:
|
||||
if var.get('name') == name:
|
||||
return var
|
||||
if 'children' in var:
|
||||
found = find_var_by_name(var['children'], name)
|
||||
if found:
|
||||
return found
|
||||
return None
|
||||
|
||||
|
||||
def add_to_nested_tree(tree, var, path_parts, full_names=None, depth=0, source_tree=None):
|
||||
if not path_parts:
|
||||
return
|
||||
|
||||
if full_names is None:
|
||||
full_names = build_full_names(path_parts, var['name'])
|
||||
|
||||
current_name = full_names[depth]
|
||||
|
||||
for child in tree:
|
||||
if child.get('name') == current_name:
|
||||
if depth == len(path_parts) - 1:
|
||||
child.update(var)
|
||||
return
|
||||
if 'children' not in child:
|
||||
child['children'] = []
|
||||
add_to_nested_tree(child['children'], var, path_parts, full_names, depth + 1, source_tree)
|
||||
return
|
||||
|
||||
# Ищем в source_tree (expanded_vars) родительский узел по current_name
|
||||
parent_data = {}
|
||||
if source_tree:
|
||||
parent_var = find_var_by_name(source_tree, current_name)
|
||||
if parent_var:
|
||||
# Копируем все поля кроме детей (children)
|
||||
parent_data = {k: v for k, v in parent_var.items() if k != 'children'}
|
||||
|
||||
new_node = {
|
||||
'name': current_name,
|
||||
'children': []
|
||||
}
|
||||
|
||||
# Обновляем new_node данными родителя
|
||||
new_node.update(parent_data)
|
||||
|
||||
if depth == len(path_parts) - 1:
|
||||
new_node.update(var)
|
||||
else:
|
||||
add_to_nested_tree(new_node['children'], var, path_parts, full_names, depth + 1, source_tree)
|
||||
|
||||
tree.append(new_node)
|
||||
|
||||
|
||||
|
||||
|
||||
def split_vars_by_show_flag(expanded_vars):
|
||||
from copy import deepcopy
|
||||
|
||||
unselected_vars = deepcopy(expanded_vars)
|
||||
selected_vars = []
|
||||
|
||||
def recurse(vars_list):
|
||||
for var in vars_list:
|
||||
show_var = var.get('show_var', 'false').lower()
|
||||
if show_var == 'true':
|
||||
selected_vars.append(var)
|
||||
def find_and_remove(var_list, target_name):
|
||||
"""Удаляет элемент по полному имени и возвращает его"""
|
||||
for i, var in enumerate(var_list):
|
||||
if var.get("name") == target_name:
|
||||
return var_list.pop(i)
|
||||
if 'children' in var:
|
||||
found = find_and_remove(var['children'], target_name)
|
||||
if found:
|
||||
return found
|
||||
return None
|
||||
|
||||
# Рекурсивно обходим детей, если есть
|
||||
children = var.get('children')
|
||||
if children:
|
||||
recurse(children)
|
||||
def collect_selected_nodes(var):
|
||||
"""Рекурсивно возвращает все show_var=true узлы (включая поддерево)"""
|
||||
nodes = []
|
||||
if var.get('show_var', 'false').lower() == 'true':
|
||||
nodes.append(var)
|
||||
for child in var.get('children', []):
|
||||
nodes.extend(collect_selected_nodes(child))
|
||||
return nodes
|
||||
|
||||
recurse(expanded_vars)
|
||||
return selected_vars
|
||||
selected_nodes = []
|
||||
for var in expanded_vars:
|
||||
selected_nodes.extend(collect_selected_nodes(var))
|
||||
|
||||
for node in selected_nodes:
|
||||
path_parts = split_path(node['name'])
|
||||
|
||||
# Вырезать из unselected_vars
|
||||
removed = find_and_remove(unselected_vars, node['name'])
|
||||
if removed:
|
||||
add_to_nested_tree(selected_vars, removed, path_parts)
|
||||
else:
|
||||
# вдруг удалённый родитель — создаём вручную
|
||||
add_to_nested_tree(selected_vars, node, path_parts)
|
||||
|
||||
return selected_vars, unselected_vars
|
||||
|
||||
Reference in New Issue
Block a user