debugVarTool/Src/scan_progress_gui.py
Razvalyaev 369cfa808c чистка для релиза
переструктурировано чуть

и всякие мелкие фиксы
2025-07-15 15:37:29 +03:00

219 lines
7.9 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 sys
import re
import multiprocessing
import sys
import contextlib
import io
import json
from scan_vars import run_scan
from var_table import VariableTableWidget, rows
from PySide2.QtWidgets import (
QApplication, QWidget, QTableWidget, QTableWidgetItem,
QCheckBox, QComboBox, QLineEdit, QVBoxLayout, QHBoxLayout, QPushButton,
QCompleter, QAbstractItemView, QLabel, QMessageBox, QFileDialog, QTextEdit,
QDialog, QTreeWidget, QTreeWidgetItem, QSizePolicy, QHeaderView, QProgressBar
)
from PySide2.QtGui import QTextCursor, QKeyEvent
from PySide2.QtCore import Qt, QProcess, QObject, Signal, QTimer
class EmittingStream(QObject):
text_written = Signal(str)
progress_updated = Signal(str, int, int) # bar_name, current, total
def __init__(self):
super().__init__()
self._buffer = ""
self._current_bar_name = None
def write(self, text):
self._buffer += text
while '\n' in self._buffer:
line, self._buffer = self._buffer.split('\n', 1)
if line.startswith('Progress: "') and line.endswith('"'):
bar_name = self._extract_bar_name(line)
if bar_name:
self._current_bar_name = bar_name
continue # не выводим строку
elif self._is_progress_line(line):
current, total = self._extract_progress(line)
if current is not None and total is not None:
name = self._current_bar_name if self._current_bar_name else "Progress"
self.progress_updated.emit(name, current, total)
continue # не выводим строку
# если не прогресс и не имя — выводим
self.text_written.emit(line)
def _extract_bar_name(self, line):
# точно обрезаем вручную
prefix = 'Progress: "'
suffix = '"'
if line.startswith(prefix) and line.endswith(suffix):
return line[len(prefix):-1]
return None
def _is_progress_line(self, line):
return re.match(r'^Progress:\s*\d+\s*/\s*\d+$', line) is not None
def _extract_progress(self, line):
match = re.match(r'^Progress:\s*(\d+)\s*/\s*(\d+)$', line)
if match:
return int(match.group(1)), int(match.group(2))
return None, None
def flush(self):
if self._buffer:
line = self._buffer.strip()
if not self._is_progress_line(line) and not self._extract_bar_name(line):
self.text_written.emit(line)
self._buffer = ""
class ProcessOutputWindow(QDialog):
def __init__(self, proj_path, makefile_path, xml_path, on_done_callback=None, parent=None):
super().__init__(parent)
self.setWindowTitle("Поиск переменных...")
self.resize(600, 480)
self.setModal(True)
self.setAttribute(Qt.WA_DeleteOnClose)
self.proj_path = proj_path
self.makefile_path = makefile_path
self.xml_path = xml_path
self._on_done_callback = on_done_callback
self.layout = QVBoxLayout(self)
self.output_edit = QTextEdit()
self.output_edit.setReadOnly(True)
self.layout.addWidget(self.output_edit)
self.progress_label = QLabel("Progress:")
self.layout.addWidget(self.progress_label)
self.progress_bar = QProgressBar()
self.progress_bar.setMinimum(0)
self.progress_bar.setValue(0)
self.layout.addWidget(self.progress_bar)
self.btn_close = QPushButton("Закрыть")
self.btn_close.setEnabled(False)
self.layout.addWidget(self.btn_close)
self.btn_close.clicked.connect(self.__handle_done)
self.queue = None
self.proc = None
def start_scan(self):
self.queue = multiprocessing.Queue()
self.proc = multiprocessing.Process(
target=run_scan_process,
args=(self.proj_path, self.makefile_path, self.xml_path, self.queue),
daemon=True)
self.proc.start()
self.timer = QTimer(self)
self.timer.timeout.connect(self.poll_queue)
self.timer.start(100)
self.show()
def poll_queue(self):
try:
while True:
msg = self.queue.get_nowait()
if msg is None:
# Конец процесса
self.btn_close.setEnabled(True)
self.append_text("\n--- Анализ завершён ---")
self.timer.stop()
return
# Пытаемся разобрать JSON-сообщение
if isinstance(msg, str) and msg.startswith("PROGRESS_MSG:"):
try:
data = json.loads(msg[len("PROGRESS_MSG:"):])
self.update_progress(data["bar_name"], data["current"], data["total"])
except Exception:
# Если не удалось распарсить, выводим как текст
self.append_text(msg)
else:
self.append_text(msg)
except Exception:
pass # Очередь пустая
def append_text(self, text):
cursor = self.output_edit.textCursor()
cursor.movePosition(QTextCursor.End)
if not text.endswith('\n'):
text += '\n'
cursor.insertText(text)
self.output_edit.setTextCursor(cursor)
self.output_edit.ensureCursorVisible()
def update_progress(self, bar_name, current, total):
self.progress_label.setText(f"{bar_name}")
self.progress_bar.setMaximum(total)
self.progress_bar.setValue(current)
def __handle_done(self):
self.close()
def closeEvent(self, event):
if self.proc and self.proc.is_alive():
self.proc.terminate()
self.proc.join()
self.btn_close.setEnabled(True)
self.append_text("Сканирование прервано.")
def run_scan_process(proj_path, makefile_path, xml_path, queue):
class QueueWriter(io.TextIOBase):
def __init__(self):
self._buffer = ""
self._current_bar_name = None
def write(self, txt):
self._buffer += txt
while '\n' in self._buffer:
line, self._buffer = self._buffer.split('\n', 1)
# Обработка прогресса
if line.startswith('Progress: "') and line.endswith('"'):
# Название прогресс-бара
bar_name = line[len('Progress: "'):-1]
self._current_bar_name = bar_name
elif re.match(r'^Progress:\s*\d+\s*/\s*\d+$', line):
m = re.match(r'^Progress:\s*(\d+)\s*/\s*(\d+)$', line)
if m:
current = int(m.group(1))
total = int(m.group(2))
bar_name = self._current_bar_name or "Progress"
# Отправляем специальное сообщение в очередь в формате JSON
msg = {
"bar_name": bar_name,
"current": current,
"total": total
}
queue.put("PROGRESS_MSG:" + json.dumps(msg))
else:
# Обычный вывод
queue.put(line)
def flush(self):
if self._buffer.strip():
queue.put(self._buffer.strip())
self._buffer = ""
sys.stdout = QueueWriter()
sys.stderr = sys.stdout
try:
run_scan(proj_path, makefile_path, xml_path)
except Exception as e:
queue.put(f"[ОШИБКА] {e}")
finally:
queue.put(None) # сигнал окончания