forked from CastroFidel/winehelper
Compare commits
1 Commits
quote_butt
...
download_p
Author | SHA1 | Date | |
---|---|---|---|
9611cc52fc |
@ -2,6 +2,7 @@
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
import shlex
|
||||
import shutil
|
||||
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,QPushButton, QLabel, QTabWidget,
|
||||
@ -64,7 +65,6 @@ class WineHelperGUI(QMainWindow):
|
||||
self.process = None
|
||||
self.current_script = None
|
||||
self.install_process = None
|
||||
self.current_display_name = None
|
||||
self.install_dialog = None
|
||||
self.current_active_button = None
|
||||
self.installed_buttons = []
|
||||
@ -90,6 +90,9 @@ class WineHelperGUI(QMainWindow):
|
||||
self.create_installed_tab()
|
||||
self.create_help_tab()
|
||||
|
||||
# Инициализируем состояние, которое будет использоваться для логов
|
||||
self._reset_log_state()
|
||||
|
||||
# Обновляем список установленных приложений
|
||||
self.update_installed_apps()
|
||||
|
||||
@ -163,7 +166,7 @@ class WineHelperGUI(QMainWindow):
|
||||
|
||||
# Заголовок
|
||||
self.script_title = QLabel("Выберите программу")
|
||||
self.script_title.setFont(QFont('Arial', 12, QFont.Bold)) # Шрифт и размер шрифта в заголовке инф. панели
|
||||
self.script_title.setFont(QFont('Arial', 14, QFont.Bold)) # Шрифт и размер шрифта в заголовке инф. панели
|
||||
self.script_title.setAlignment(Qt.AlignCenter)
|
||||
self.info_panel_layout.addWidget(self.script_title)
|
||||
|
||||
@ -199,7 +202,7 @@ class WineHelperGUI(QMainWindow):
|
||||
install_action_layout = QVBoxLayout()
|
||||
install_action_layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.install_button = QPushButton("Установить")
|
||||
self.install_button.setFont(QFont('Arial', 12, QFont.Bold)) # Шрифт и размер шрифта в кнопке Установить
|
||||
self.install_button.setFont(QFont('Arial', 13, QFont.Bold))
|
||||
self.install_button.setStyleSheet("background-color: #4CAF50; color: white;")
|
||||
self.install_button.clicked.connect(self.install_current_script)
|
||||
install_action_layout.addWidget(self.install_button)
|
||||
@ -834,11 +837,6 @@ class WineHelperGUI(QMainWindow):
|
||||
print(f"Error getting prefix name from {desktop_file}: {e}")
|
||||
return None
|
||||
|
||||
def _get_current_app_title(self):
|
||||
"""Возвращает отображаемое имя для текущей выбранной программы."""
|
||||
# Если display_name не установлено (например, при ошибке), используем имя скрипта
|
||||
return self.current_display_name or self.current_script
|
||||
|
||||
def backup_prefix_for_app(self):
|
||||
"""Создает резервную копию префикса для выбранного приложения."""
|
||||
prefix_name = self._get_prefix_name_for_selected_app()
|
||||
@ -1212,7 +1210,6 @@ class WineHelperGUI(QMainWindow):
|
||||
prog_name = self.extract_prog_name_from_script(script_path)
|
||||
prog_url = self.extract_prog_url_from_script(script_path)
|
||||
display_name = prog_name if prog_name else script_name
|
||||
self.current_display_name = display_name
|
||||
|
||||
if icon_names:
|
||||
# Для заголовка используем первую иконку из списка
|
||||
@ -1235,7 +1232,7 @@ class WineHelperGUI(QMainWindow):
|
||||
self.install_action_widget.setVisible(True)
|
||||
self.installed_action_widget.setVisible(False)
|
||||
self.installed_global_action_widget.setVisible(False)
|
||||
self.install_button.setText(f"Установить «{display_name}»")
|
||||
self.install_button.setText(f"Установить {display_name}")
|
||||
|
||||
def install_current_script(self):
|
||||
"""Устанавливает текущий выбранный скрипт"""
|
||||
@ -1249,8 +1246,7 @@ class WineHelperGUI(QMainWindow):
|
||||
|
||||
# Создаем диалоговое окно установки
|
||||
self.install_dialog = QDialog(self)
|
||||
title_name = self._get_current_app_title()
|
||||
self.install_dialog.setWindowTitle(f"Установка «{title_name}»")
|
||||
self.install_dialog.setWindowTitle(f"Установка {self.current_script}")
|
||||
self.install_dialog.setMinimumSize(750, 400)
|
||||
self.install_dialog.setWindowModality(Qt.WindowModal)
|
||||
|
||||
@ -1343,10 +1339,16 @@ class WineHelperGUI(QMainWindow):
|
||||
|
||||
self.install_dialog.show()
|
||||
|
||||
def _reset_log_state(self):
|
||||
"""Сбрасывает состояние буфера и флага прогресса для лога установки."""
|
||||
self.output_buffer = ""
|
||||
self.last_line_was_progress = False
|
||||
|
||||
def _prepare_installation(self):
|
||||
"""Подготавливает и запускает процесс установки"""
|
||||
self.stacked_widget.setCurrentIndex(1)
|
||||
|
||||
self._reset_log_state() # Сбрасываем состояние для обработки лога
|
||||
|
||||
winehelper_path = self.winehelper_path
|
||||
script_path = os.path.join(Var.DATA_PATH,
|
||||
"autoinstall" if self.current_script in self.autoinstall_scripts else "manualinstall",
|
||||
@ -1385,8 +1387,7 @@ class WineHelperGUI(QMainWindow):
|
||||
if install_file:
|
||||
args.append(install_file)
|
||||
|
||||
title_name = self._get_current_app_title()
|
||||
self.append_log(f"=== Начало установки «{title_name}» ===")
|
||||
self.append_log(f"=== Начало установки {self.current_script} ===")
|
||||
self.append_log(f"Исполняемый файл: {winehelper_path}")
|
||||
self.append_log(f"Аргументы: {' '.join(shlex.quote(a) for a in args)}")
|
||||
|
||||
@ -1400,35 +1401,99 @@ class WineHelperGUI(QMainWindow):
|
||||
QMessageBox.critical(self.install_dialog, "Ошибка", f"Не удалось запустить установку:\n{str(e)}")
|
||||
self.cleanup_process()
|
||||
|
||||
def append_log(self, text, is_error=False):
|
||||
def append_log(self, text, is_error=False, add_newline=True):
|
||||
"""Добавляет сообщение в лог"""
|
||||
if not hasattr(self, 'log_output'): return
|
||||
cursor = self.log_output.textCursor()
|
||||
cursor.movePosition(QTextCursor.End)
|
||||
|
||||
if is_error:
|
||||
# Для ошибок всегда добавляем перенос строки для лучшей читаемости
|
||||
cursor.insertHtml(f'<font color="red">{text}</font><br>')
|
||||
else:
|
||||
cursor.insertText(f"{text}\n")
|
||||
# Вставляем текст. Добавляем перенос строки, если нужно.
|
||||
formatted_text = f"{text}\n" if add_newline else text
|
||||
cursor.insertText(formatted_text)
|
||||
|
||||
self.log_output.ensureCursorVisible()
|
||||
QApplication.processEvents()
|
||||
|
||||
def _process_log_line(self, line_with_delimiter):
|
||||
"""Обрабатывает одну строку лога, управляя заменой строк прогресса."""
|
||||
is_progress_line = '\r' in line_with_delimiter
|
||||
|
||||
# Фильтруем "мусорные" строки прогресса (например, '-=O=-' от wget),
|
||||
# обрабатывая только те, что содержат знак процента.
|
||||
if is_progress_line:
|
||||
if not re.search(r'\d\s*%', line_with_delimiter):
|
||||
return # Игнорируем строку прогресса без процентов
|
||||
|
||||
clean_line = line_with_delimiter.replace('\r', '').replace('\n', '').strip()
|
||||
|
||||
if not clean_line:
|
||||
return
|
||||
|
||||
cursor = self.log_output.textCursor()
|
||||
|
||||
# Если новая строка - это прогресс, и предыдущая тоже была прогрессом,
|
||||
# то мы удаляем старую, чтобы заменить ее новой.
|
||||
if is_progress_line and self.last_line_was_progress:
|
||||
cursor.movePosition(QTextCursor.End)
|
||||
cursor.select(QTextCursor.LineUnderCursor)
|
||||
cursor.removeSelectedText()
|
||||
elif not is_progress_line and self.last_line_was_progress:
|
||||
# Это переход от строки прогресса к финальной строке.
|
||||
# Вместо добавления переноса, мы заменяем предыдущую строку новой.
|
||||
cursor.movePosition(QTextCursor.End)
|
||||
cursor.select(QTextCursor.LineUnderCursor)
|
||||
cursor.removeSelectedText()
|
||||
|
||||
# Добавляем новую очищенную строку.
|
||||
# Для прогресса - без переноса строки, для обычных строк - с переносом.
|
||||
self.append_log(clean_line, add_newline=not is_progress_line)
|
||||
|
||||
self.last_line_was_progress = is_progress_line
|
||||
|
||||
def handle_process_output(self):
|
||||
"""Обрабатывает вывод процесса"""
|
||||
output = self.install_process.readAllStandardOutput().data().decode('utf-8', errors='ignore').strip()
|
||||
if output:
|
||||
self.append_log(output)
|
||||
"""Обрабатывает вывод процесса, корректно отображая однострочный прогресс."""
|
||||
new_data = self.install_process.readAllStandardOutput().data().decode('utf-8', errors='ignore')
|
||||
self.output_buffer += new_data
|
||||
|
||||
while True:
|
||||
# Ищем ближайший разделитель (\n или \r)
|
||||
idx_n = self.output_buffer.find('\n')
|
||||
idx_r = self.output_buffer.find('\r')
|
||||
|
||||
if idx_n == -1 and idx_r == -1:
|
||||
break # Нет полных строк для обработки
|
||||
|
||||
split_idx = min(idx for idx in [idx_n, idx_r] if idx != -1)
|
||||
|
||||
# Получаем строку, включая разделитель
|
||||
line = self.output_buffer[:split_idx + 1]
|
||||
self.output_buffer = self.output_buffer[split_idx + 1:]
|
||||
|
||||
self._process_log_line(line)
|
||||
|
||||
def handle_process_finished(self, exit_code, exit_status):
|
||||
"""Обрабатывает завершение процесса"""
|
||||
# Обрабатываем остаток в буфере, если он есть
|
||||
if self.output_buffer:
|
||||
self._process_log_line(self.output_buffer)
|
||||
|
||||
# Если последней строкой был прогресс, "завершаем" его переносом строки.
|
||||
if self.last_line_was_progress:
|
||||
cursor = self.log_output.textCursor()
|
||||
cursor.movePosition(QTextCursor.End)
|
||||
cursor.insertText("\n")
|
||||
|
||||
self._reset_log_state()
|
||||
if exit_code == 0 and exit_status == QProcess.NormalExit:
|
||||
self.append_log("\n=== Установка успешно завершена ===")
|
||||
# Создаем кастомный диалог, чтобы кнопка была на русском
|
||||
success_box = QMessageBox(self.install_dialog)
|
||||
success_box.setWindowTitle("Успех")
|
||||
title_name = self._get_current_app_title()
|
||||
success_box.setText(f"Программа «{title_name}» установлена успешно!")
|
||||
success_box.setText(f"Программа {self.current_script} установлена успешно!")
|
||||
success_box.setIcon(QMessageBox.Information)
|
||||
success_box.addButton("Готово", QMessageBox.AcceptRole)
|
||||
success_box.exec_()
|
||||
|
Reference in New Issue
Block a user