forked from CastroFidel/winehelper
(gui): improved error handling
This commit is contained in:
@@ -17,6 +17,7 @@ from PyQt5.QtCore import Qt, QProcess, QSize, QTimer, QProcessEnvironment, QProp
|
||||
from PyQt5.QtGui import QIcon, QFont, QTextCursor, QPixmap, QPainter, QCursor, QTextCharFormat, QColor, QPalette
|
||||
from PyQt5.QtNetwork import QLocalServer, QLocalSocket
|
||||
from typing import Optional, Dict, Any, Callable, List, Set, Tuple, Union
|
||||
import traceback
|
||||
|
||||
|
||||
class Var:
|
||||
@@ -35,6 +36,32 @@ class Var:
|
||||
WH_WINETRICKS: Optional[str] = os.environ.get("WH_WINETRICKS")
|
||||
|
||||
|
||||
class ErrorReporter:
|
||||
"""Утилита для централизованного отчета об ошибках."""
|
||||
|
||||
@staticmethod
|
||||
def show_error(parent, title: str, message: str, detailed_text: Optional[str] = None):
|
||||
"""Показывает диалог с сообщением об ошибке."""
|
||||
msg_box = QMessageBox(parent)
|
||||
msg_box.setIcon(QMessageBox.Critical)
|
||||
msg_box.setWindowTitle(title)
|
||||
msg_box.setText(message)
|
||||
|
||||
if detailed_text:
|
||||
msg_box.setDetailedText(detailed_text)
|
||||
|
||||
msg_box.exec_()
|
||||
|
||||
@staticmethod
|
||||
def log_error(message: str, exception: Optional[Exception] = None):
|
||||
"""Логирует ошибку в консоль."""
|
||||
if exception:
|
||||
detailed_error = f"{message}\n{traceback.format_exc()}"
|
||||
print(detailed_error)
|
||||
else:
|
||||
print(f"ERROR: {message}")
|
||||
|
||||
|
||||
class WinetricksManagerDialog(QDialog):
|
||||
"""Диалог для управления компонентами Winetricks."""
|
||||
|
||||
@@ -684,8 +711,17 @@ class ScriptParser:
|
||||
except (ValueError, IndexError):
|
||||
continue
|
||||
return icon_names
|
||||
except FileNotFoundError:
|
||||
print(f"Ошибка: файл скрипта не найден для извлечения иконки: {script_path}")
|
||||
return []
|
||||
except PermissionError:
|
||||
print(f"Ошибка: нет доступа к файлу скрипта для извлечения иконки: {script_path}")
|
||||
return []
|
||||
except UnicodeDecodeError:
|
||||
print(f"Ошибка: невозможно декодировать файл скрипта (неподдерживаемая кодировка): {script_path}")
|
||||
return []
|
||||
except Exception as e:
|
||||
print(f"Ошибка чтения файла для извлечения иконки: {str(e)}")
|
||||
print(f"Неизвестная ошибка при чтении файла для извлечения иконки {script_path}: {str(e)}")
|
||||
return []
|
||||
|
||||
@staticmethod
|
||||
@@ -699,8 +735,17 @@ class ScriptParser:
|
||||
if name:
|
||||
return name
|
||||
return None
|
||||
except FileNotFoundError:
|
||||
print(f"Ошибка: файл скрипта не найден для извлечения PROG_NAME: {script_path}")
|
||||
return None
|
||||
except PermissionError:
|
||||
print(f"Ошибка: нет доступа к файлу скрипта для извлечения PROG_NAME: {script_path}")
|
||||
return None
|
||||
except UnicodeDecodeError:
|
||||
print(f"Ошибка: невозможно декодировать файл скрипта (неподдерживаемая кодировка): {script_path}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Ошибка чтения файла для извлечения PROG_NAME: {str(e)}")
|
||||
print(f"Неизвестная ошибка при чтении файла для извлечения PROG_NAME {script_path}: {str(e)}")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
@@ -712,8 +757,17 @@ class ScriptParser:
|
||||
if line.startswith('export PROG_URL='):
|
||||
return line.replace('export PROG_URL=', '').strip().strip('"\'')
|
||||
return None
|
||||
except FileNotFoundError:
|
||||
print(f"Ошибка: файл скрипта не найден для извлечения PROG_URL: {script_path}")
|
||||
return None
|
||||
except PermissionError:
|
||||
print(f"Ошибка: нет доступа к файлу скрипта для извлечения PROG_URL: {script_path}")
|
||||
return None
|
||||
except UnicodeDecodeError:
|
||||
print(f"Ошибка: невозможно декодировать файл скрипта (неподдерживаемая кодировка): {script_path}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Ошибка чтения файла для извлечения PROG_URL: {str(e)}")
|
||||
print(f"Неизвестная ошибка при чтении файла для извлечения PROG_URL {script_path}: {str(e)}")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
@@ -725,8 +779,14 @@ class ScriptParser:
|
||||
if line.startswith('# info_ru:'):
|
||||
return line.replace('# info_ru:', '').strip()
|
||||
return "Описание отсутствует"
|
||||
except FileNotFoundError:
|
||||
return f"Ошибка: файл скрипта не найден: {script_path}"
|
||||
except PermissionError:
|
||||
return f"Ошибка: нет доступа к файлу скрипта: {script_path}"
|
||||
except UnicodeDecodeError:
|
||||
return f"Ошибка: невозможно декодировать файл скрипта (неподдерживаемая кодировка): {script_path}"
|
||||
except Exception as e:
|
||||
return f"Ошибка чтения файла: {str(e)}"
|
||||
return f"Неизвестная ошибка при чтении файла {script_path}: {str(e)}"
|
||||
|
||||
class WineVersionSelectionDialog(QDialog):
|
||||
"""Диалог для выбора версии Wine/Proton с группировкой."""
|
||||
@@ -811,8 +871,17 @@ class WineVersionSelectionDialog(QDialog):
|
||||
if filename.endswith('.tar.xz'):
|
||||
version_name = filename[:-7]
|
||||
self.wine_versions_data[current_group].append(version_name)
|
||||
except IOError as e:
|
||||
QMessageBox.warning(self, "Ошибка", f"Не удалось прочитать файл версий:\n{e}")
|
||||
except FileNotFoundError:
|
||||
QMessageBox.critical(self, "Ошибка", f"Файл с версиями не найден:\n{sha256_path}")
|
||||
self.wine_versions_data = {}
|
||||
except PermissionError:
|
||||
QMessageBox.critical(self, "Ошибка", f"Нет доступа к файлу с версиями:\n{sha256_path}")
|
||||
self.wine_versions_data = {}
|
||||
except UnicodeDecodeError:
|
||||
QMessageBox.critical(self, "Ошибка", f"Невозможно декодировать файл с версиями (неподдерживаемая кодировка):\n{sha256_path}")
|
||||
self.wine_versions_data = {}
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Ошибка", f"Неизвестная ошибка при чтении файла версий:\n{str(e)}")
|
||||
self.wine_versions_data = {}
|
||||
|
||||
def _get_installed_versions(self) -> List[str]:
|
||||
@@ -1160,8 +1229,14 @@ class CreatePrefixDialog(QDialog):
|
||||
if arch:
|
||||
self.prepared_prefixes[arch].append((current_prefix_name, current_description.strip().replace('\\n', '\n')))
|
||||
|
||||
except IOError as e:
|
||||
QMessageBox.warning(self, "Ошибка", f"Не удалось прочитать файл с описаниями префиксов: {e}")
|
||||
except FileNotFoundError:
|
||||
QMessageBox.critical(self, "Ошибка", f"Файл с описаниями префиксов не найден: {sha256_file}")
|
||||
except PermissionError:
|
||||
QMessageBox.critical(self, "Ошибка", f"Нет доступа к файлу с описаниями префиксов: {sha256_file}")
|
||||
except UnicodeDecodeError:
|
||||
QMessageBox.critical(self, "Ошибка", f"Невозможно декодировать файл с описаниями префиксов (неподдерживаемая кодировка): {sha256_file}")
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Ошибка", f"Неизвестная ошибка при чтении файла с описаниями префиксов: {str(e)}")
|
||||
|
||||
# Добавляем опцию "Чистый префикс" для обеих архитектур
|
||||
self.prepared_prefixes['win32'].insert(0, ('none', 'Создать чистый префикс без дополнительных библиотек'))
|
||||
@@ -1226,16 +1301,19 @@ class CreatePrefixDialog(QDialog):
|
||||
prefix_name = self.prefix_name_edit.text().strip()
|
||||
|
||||
if not prefix_name:
|
||||
QMessageBox.warning(self, "Ошибка", "Имя префикса не может быть пустым.")
|
||||
error_msg = "Имя префикса не может быть пустым."
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
return
|
||||
|
||||
if not re.match(r'^[a-zA-Z0-9_-]+$', prefix_name):
|
||||
QMessageBox.warning(self, "Ошибка", "Имя префикса может содержать только латинские буквы, цифры, дефисы и знаки подчеркивания.")
|
||||
error_msg = "Имя префикса может содержать только латинские буквы, цифры, дефисы и знаки подчеркивания."
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
return
|
||||
|
||||
prefix_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name)
|
||||
if os.path.exists(prefix_path):
|
||||
QMessageBox.warning(self, "Ошибка", f"Префикс с именем '{prefix_name}' уже существует.")
|
||||
error_msg = f"Префикс с именем '{prefix_name}' уже существует."
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
return
|
||||
|
||||
# Save data
|
||||
@@ -1303,15 +1381,9 @@ class FileAssociationsDialog(QDialog):
|
||||
found_forbidden = entered_extensions.intersection(forbidden_extensions)
|
||||
|
||||
if found_forbidden:
|
||||
msg_box = QMessageBox(self)
|
||||
msg_box.setIcon(QMessageBox.Warning)
|
||||
msg_box.setWindowTitle("Недопустимые расширения")
|
||||
msg_box.setTextFormat(Qt.RichText)
|
||||
msg_box.setText(
|
||||
"Следующие расширения запрещены и не могут быть использованы:<br><br>"
|
||||
f"<b>{', '.join(sorted(list(found_forbidden)))}</b>"
|
||||
)
|
||||
msg_box.exec_()
|
||||
error_msg = "Следующие расширения запрещены и не могут быть использованы:<br><br>" \
|
||||
f"<b>{', '.join(sorted(list(found_forbidden)))}</b>"
|
||||
ErrorReporter.show_error(self, "Недопустимые расширения", error_msg)
|
||||
return
|
||||
|
||||
# Сохраняем результат в виде отсортированной строки
|
||||
@@ -1401,7 +1473,17 @@ class ComponentVersionSelectionDialog(QDialog):
|
||||
if filename.endswith('.tar.xz'):
|
||||
version_name = filename[:-7]
|
||||
self.versions_data.append(version_name)
|
||||
except IOError:
|
||||
except FileNotFoundError:
|
||||
print(f"Ошибка: файл с версиями компонента не найден: {sha256_path}")
|
||||
self.versions_data = []
|
||||
except PermissionError:
|
||||
print(f"Ошибка: нет доступа к файлу с версиями компонента: {sha256_path}")
|
||||
self.versions_data = []
|
||||
except UnicodeDecodeError:
|
||||
print(f"Ошибка: невозможно декодировать файл с версиями компонента (неподдерживаемая кодировка): {sha256_path}")
|
||||
self.versions_data = []
|
||||
except Exception as e:
|
||||
print(f"Неизвестная ошибка при чтении файла версий компонента {sha256_path}: {str(e)}")
|
||||
self.versions_data = []
|
||||
|
||||
def populate_ui(self, start_row: int) -> None:
|
||||
@@ -2532,7 +2614,8 @@ class WineHelperGUI(QMainWindow):
|
||||
self._remove_prefix_from_gui_state(prefix_name)
|
||||
self.update_installed_apps()
|
||||
else:
|
||||
QMessageBox.critical(self, "Ошибка удаления", f"Не удалось удалить префикс '{prefix_name}'.\nПодробности смотрите в логе.")
|
||||
error_msg = f"Не удалось удалить префикс '{prefix_name}'.\nПодробности смотрите в логе."
|
||||
ErrorReporter.show_error(self, "Ошибка удаления", error_msg)
|
||||
|
||||
def create_base_prefix_from_selected(self):
|
||||
"""Создает шаблон префикса из выбранного в выпадающем списке."""
|
||||
@@ -2588,8 +2671,15 @@ class WineHelperGUI(QMainWindow):
|
||||
if os.path.isdir(prefix_path):
|
||||
try:
|
||||
subprocess.Popen(['xdg-open', prefix_path])
|
||||
except FileNotFoundError:
|
||||
error_msg = "Команда 'xdg-open' не найдена. Убедитесь, что у вас установлен файловый менеджер по умолчанию."
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
except PermissionError:
|
||||
error_msg = f"Нет доступа к директории префикса:\n{prefix_path}"
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
except Exception as e:
|
||||
QMessageBox.warning(self, "Ошибка", f"Не удалось открыть директорию:\n{prefix_path}\n\nОшибка: {e}")
|
||||
error_msg = f"Не удалось открыть директорию:\n{prefix_path}\n\nОшибка: {e}"
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg, traceback.format_exc())
|
||||
else:
|
||||
QMessageBox.warning(self, "Ошибка", f"Директория префикса не найдена:\n{prefix_path}")
|
||||
|
||||
@@ -2636,8 +2726,17 @@ class WineHelperGUI(QMainWindow):
|
||||
key = parts[0].strip()
|
||||
value = parts[1].strip().strip('"\'')
|
||||
all_vars[key] = value
|
||||
except IOError as e:
|
||||
self.prefix_info_display.setHtml(f"<p>Ошибка чтения last.conf: {e}</p>")
|
||||
except FileNotFoundError:
|
||||
self.prefix_info_display.setHtml(f"<p>Файл конфигурации last.conf не найден для префикса '{prefix_name}'.</p>")
|
||||
return
|
||||
except PermissionError:
|
||||
self.prefix_info_display.setHtml(f"<p>Нет доступа к файлу конфигурации last.conf для префикса '{prefix_name}'.</p>")
|
||||
return
|
||||
except UnicodeDecodeError:
|
||||
self.prefix_info_display.setHtml(f"<p>Невозможно декодировать файл конфигурации last.conf (неподдерживаемая кодировка) для префикса '{prefix_name}'.</p>")
|
||||
return
|
||||
except Exception as e:
|
||||
self.prefix_info_display.setHtml(f"<p>Ошибка чтения last.conf для префикса '{prefix_name}': {str(e)}</p>")
|
||||
return
|
||||
|
||||
# --- Обновить кнопки ESync/FSync ---
|
||||
@@ -2661,8 +2760,14 @@ class WineHelperGUI(QMainWindow):
|
||||
verb = line.split('#', 1)[0].strip()
|
||||
if verb:
|
||||
installed_verbs.append(verb)
|
||||
except IOError as e:
|
||||
print(f"Ошибка чтения winetricks.log: {e}")
|
||||
except FileNotFoundError:
|
||||
print(f"Файл winetricks.log не найден для префикса '{prefix_name}': {winetricks_log_path}")
|
||||
except PermissionError:
|
||||
print(f"Нет доступа к файлу winetricks.log для префикса '{prefix_name}': {winetricks_log_path}")
|
||||
except UnicodeDecodeError:
|
||||
print(f"Невозможно декодировать файл winetricks.log (неподдерживаемая кодировка) для префикса '{prefix_name}': {winetricks_log_path}")
|
||||
except Exception as e:
|
||||
print(f"Ошибка чтения winetricks.log для префикса '{prefix_name}': {str(e)}")
|
||||
|
||||
# Фильтруем служебные компоненты, чтобы не засорять вывод
|
||||
verbs_to_ignore = {
|
||||
@@ -2784,8 +2889,17 @@ class WineHelperGUI(QMainWindow):
|
||||
value = parts[1].strip().strip('"\'')
|
||||
# Возвращаем значение, только если оно не пустое.
|
||||
return value if value else None
|
||||
except IOError as e:
|
||||
print(f"Ошибка чтения last.conf для {prefix_name}: {e}")
|
||||
except FileNotFoundError:
|
||||
print(f"Файл last.conf не найден для префикса {prefix_name}: {last_conf_path}")
|
||||
return None
|
||||
except PermissionError:
|
||||
print(f"Нет доступа к файлу last.conf для префикса {prefix_name}: {last_conf_path}")
|
||||
return None
|
||||
except UnicodeDecodeError:
|
||||
print(f"Невозможно декодировать файл last.conf (неподдерживаемая кодировка) для префикса {prefix_name}: {last_conf_path}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Ошибка чтения last.conf для {prefix_name}: {str(e)}")
|
||||
return None
|
||||
return None
|
||||
|
||||
@@ -3012,8 +3126,17 @@ class WineHelperGUI(QMainWindow):
|
||||
|
||||
with open(last_conf_path, 'w', encoding='utf-8') as f:
|
||||
f.writelines(lines)
|
||||
except IOError as e:
|
||||
QMessageBox.critical(self, "Ошибка записи", f"Не удалось обновить файл last.conf: {e}")
|
||||
except FileNotFoundError:
|
||||
QMessageBox.critical(self, "Ошибка", f"Файл last.conf не найден для префикса '{prefix_name}':\n{last_conf_path}")
|
||||
return
|
||||
except PermissionError:
|
||||
QMessageBox.critical(self, "Ошибка", f"Нет доступа к файлу last.conf для записи:\n{last_conf_path}")
|
||||
return
|
||||
except UnicodeDecodeError:
|
||||
QMessageBox.critical(self, "Ошибка", f"Невозможно декодировать файл last.conf (неподдерживаемая кодировка):\n{last_conf_path}")
|
||||
return
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Ошибка записи", f"Не удалось обновить файл last.conf: {str(e)}")
|
||||
return
|
||||
|
||||
prefix_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name)
|
||||
@@ -3106,7 +3229,7 @@ class WineHelperGUI(QMainWindow):
|
||||
|
||||
try:
|
||||
if not Var.GENERAL or not os.path.exists(Var.GENERAL):
|
||||
raise FileNotFoundError
|
||||
raise FileNotFoundError("Файл общей информации не найден")
|
||||
|
||||
with open(Var.GENERAL, 'r', encoding='utf-8') as f:
|
||||
general_content = f.read()
|
||||
@@ -3131,8 +3254,14 @@ class WineHelperGUI(QMainWindow):
|
||||
html_content += f'<p>{line}</p>'
|
||||
|
||||
general_text.setHtml(html_content)
|
||||
except (FileNotFoundError, TypeError):
|
||||
except FileNotFoundError:
|
||||
general_text.setHtml(f'<h2>Ошибка</h2><p>Не удалось загрузить файл с общей информацией по пути:<br>{Var.GENERAL}</p>')
|
||||
except PermissionError:
|
||||
general_text.setHtml(f'<h2>Ошибка</h2><p>Нет доступа к файлу с общей информацией:<br>{Var.GENERAL}</p>')
|
||||
except UnicodeDecodeError:
|
||||
general_text.setHtml(f'<h2>Ошибка</h2><p>Невозможно декодировать файл с общей информацией (неподдерживаемая кодировка):<br>{Var.GENERAL}</p>')
|
||||
except Exception as e:
|
||||
general_text.setHtml(f'<h2>Ошибка</h2><p>Произошла ошибка при чтении файла общей информации:<br>{str(e)}</p>')
|
||||
|
||||
general_layout.addWidget(general_text)
|
||||
help_subtabs.addTab(general_tab, "Общее")
|
||||
@@ -3168,7 +3297,7 @@ class WineHelperGUI(QMainWindow):
|
||||
|
||||
try:
|
||||
if not Var.LICENSE_FILE or not os.path.exists(Var.LICENSE_FILE):
|
||||
raise FileNotFoundError
|
||||
raise FileNotFoundError("Файл лицензии не найден")
|
||||
|
||||
with open(Var.LICENSE_FILE, 'r', encoding='utf-8') as f:
|
||||
license_content = f.read()
|
||||
@@ -3188,26 +3317,39 @@ class WineHelperGUI(QMainWindow):
|
||||
third_party_html = ""
|
||||
third_party_file_path = Var.THIRD_PARTY_FILE
|
||||
if third_party_file_path and os.path.exists(third_party_file_path):
|
||||
with open(third_party_file_path, 'r', encoding='utf-8') as f_tp:
|
||||
third_party_content = f_tp.read()
|
||||
try:
|
||||
with open(third_party_file_path, 'r', encoding='utf-8') as f_tp:
|
||||
third_party_content = f_tp.read()
|
||||
|
||||
# Преобразуем контент в HTML
|
||||
third_party_html += '<blockquote>'
|
||||
for line in third_party_content.splitlines():
|
||||
line = line.strip()
|
||||
if not line:
|
||||
third_party_html += '<br>'
|
||||
continue
|
||||
escaped_line = html.escape(line)
|
||||
if line.startswith('http'):
|
||||
third_party_html += f' <a href="{escaped_line}" style="font-size: 10pt;">{escaped_line}</a><br>'
|
||||
else:
|
||||
third_party_html += f'<b>{escaped_line}</b><br>'
|
||||
third_party_html += '</blockquote>'
|
||||
# Преобразуем контент в HTML
|
||||
third_party_html += '<blockquote>'
|
||||
for line in third_party_content.splitlines():
|
||||
line = line.strip()
|
||||
if not line:
|
||||
third_party_html += '<br>'
|
||||
continue
|
||||
escaped_line = html.escape(line)
|
||||
if line.startswith('http'):
|
||||
third_party_html += f' <a href="{escaped_line}" style="font-size: 10pt;">{escaped_line}</a><br>'
|
||||
else:
|
||||
third_party_html += f'<b>{escaped_line}</b><br>'
|
||||
third_party_html += '</blockquote>'
|
||||
except FileNotFoundError:
|
||||
third_party_html += f'<p>Файл THIRD-PARTY не найден по пути: {third_party_file_path}</p>'
|
||||
except PermissionError:
|
||||
third_party_html += f'<p>Нет доступа к файлу THIRD-PARTY: {third_party_file_path}</p>'
|
||||
except UnicodeDecodeError:
|
||||
third_party_html += f'<p>Невозможно декодировать файл THIRD-PARTY (неподдерживаемая кодировка): {third_party_file_path}</p>'
|
||||
except Exception as e:
|
||||
third_party_html += f'<p>Ошибка чтения файла THIRD-PARTY: {str(e)}</p>'
|
||||
|
||||
license_text.setHtml(license_html + third_party_html)
|
||||
except (FileNotFoundError, TypeError):
|
||||
except FileNotFoundError:
|
||||
license_text.setHtml(f'<h2>Лицензия</h2><p>Не удалось загрузить файл лицензии по пути:<br>{Var.LICENSE_FILE}</p>')
|
||||
except PermissionError:
|
||||
license_text.setHtml(f'<h2>Лицензия</h2><p>Нет доступа к файлу лицензии:<br>{Var.LICENSE_FILE}</p>')
|
||||
except UnicodeDecodeError:
|
||||
license_text.setHtml(f'<h2>Лицензия</h2><p>Невозможно декодировать файл лицензии (неподдерживаемая кодировка):<br>{Var.LICENSE_FILE}</p>')
|
||||
except Exception as e:
|
||||
license_text.setHtml(f'<h2>Лицензия</h2><p>Произошла ошибка при чтении файла лицензии:<br>{str(e)}</p>')
|
||||
|
||||
@@ -3223,12 +3365,16 @@ class WineHelperGUI(QMainWindow):
|
||||
|
||||
try:
|
||||
if not Var.CHANGELOG_FILE or not os.path.exists(Var.CHANGELOG_FILE):
|
||||
raise FileNotFoundError
|
||||
raise FileNotFoundError("Файл истории изменений не найден")
|
||||
with open(Var.CHANGELOG_FILE, 'r', encoding='utf-8') as f:
|
||||
changelog_content = f.read()
|
||||
changelog_text.setText(changelog_content)
|
||||
except (FileNotFoundError, TypeError):
|
||||
except FileNotFoundError:
|
||||
changelog_text.setText(f"Файл истории изменений не найден по пути:\n{Var.CHANGELOG_FILE}")
|
||||
except PermissionError:
|
||||
changelog_text.setText(f"Нет доступа к файлу истории изменений:\n{Var.CHANGELOG_FILE}")
|
||||
except UnicodeDecodeError:
|
||||
changelog_text.setText(f"Невозможно декодировать файл истории изменений (неподдерживаемая кодировка):\n{Var.CHANGELOG_FILE}")
|
||||
except Exception as e:
|
||||
changelog_text.setText(f"Не удалось прочитать файл истории изменений:\n{str(e)}")
|
||||
|
||||
@@ -3363,8 +3509,14 @@ class WineHelperGUI(QMainWindow):
|
||||
icon_file = line.split('=', 1)[1].strip()
|
||||
if os.path.exists(icon_file):
|
||||
icon_path = icon_file
|
||||
except FileNotFoundError:
|
||||
print(f"Файл .desktop не найден: {desktop_path}")
|
||||
except PermissionError:
|
||||
print(f"Нет доступа к файлу .desktop: {desktop_path}")
|
||||
except UnicodeDecodeError:
|
||||
print(f"Невозможно декодировать файл .desktop (неподдерживаемая кодировка): {desktop_path}")
|
||||
except Exception as e:
|
||||
print(f"Error reading {desktop_path}: {str(e)}")
|
||||
print(f"Ошибка чтения файла .desktop {desktop_path}: {str(e)}")
|
||||
|
||||
btn = self._create_app_button(display_name, [icon_path], self.INSTALLED_BUTTON_LIST_STYLE)
|
||||
# Обертка для рамки выделения
|
||||
@@ -3487,6 +3639,18 @@ class WineHelperGUI(QMainWindow):
|
||||
self.uninstall_button.setVisible(True)
|
||||
self.manual_install_path_widget.setVisible(False)
|
||||
|
||||
except FileNotFoundError:
|
||||
QMessageBox.critical(self, "Ошибка", f"Файл .desktop не найден:\n{desktop_path}")
|
||||
self.current_selected_app = None
|
||||
self.info_panel.setVisible(False)
|
||||
except PermissionError:
|
||||
QMessageBox.critical(self, "Ошибка", f"Нет доступа к файлу .desktop:\n{desktop_path}")
|
||||
self.current_selected_app = None
|
||||
self.info_panel.setVisible(False)
|
||||
except UnicodeDecodeError:
|
||||
QMessageBox.critical(self, "Ошибка", f"Невозможно декодировать файл .desktop (неподдерживаемая кодировка):\n{desktop_path}")
|
||||
self.current_selected_app = None
|
||||
self.info_panel.setVisible(False)
|
||||
except Exception as e:
|
||||
QMessageBox.warning(self, "Ошибка", f"Не удалось прочитать информацию о приложении: {str(e)}")
|
||||
self.current_selected_app = None
|
||||
@@ -3508,8 +3672,15 @@ class WineHelperGUI(QMainWindow):
|
||||
if os.path.isdir(log_dir_path):
|
||||
try:
|
||||
subprocess.Popen(['xdg-open', log_dir_path])
|
||||
except FileNotFoundError:
|
||||
error_msg = "Команда 'xdg-open' не найдена. Убедитесь, что у вас установлен файловый менеджер по умолчанию."
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
except PermissionError:
|
||||
error_msg = f"Нет доступа к директории с логами:\n{log_dir_path}"
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
except Exception as e:
|
||||
QMessageBox.warning(self, "Ошибка", f"Не удалось открыть директорию:\n{log_dir_path}\n\nОшибка: {e}")
|
||||
error_msg = f"Не удалось открыть директорию:\n{log_dir_path}\n\nОшибка: {e}"
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg, traceback.format_exc())
|
||||
else:
|
||||
QMessageBox.information(self, "Информация", f"Директория с логами не найдена:\n{log_dir_path}")
|
||||
|
||||
@@ -3530,8 +3701,14 @@ class WineHelperGUI(QMainWindow):
|
||||
prefix_part = exec_line.split("prefixes/")[1].split("/")[0]
|
||||
if prefix_part:
|
||||
return prefix_part
|
||||
except FileNotFoundError:
|
||||
print(f"Файл .desktop не найден при попытке получить имя префикса: {desktop_file}")
|
||||
except PermissionError:
|
||||
print(f"Нет доступа к файлу .desktop при попытке получить имя префикса: {desktop_file}")
|
||||
except UnicodeDecodeError:
|
||||
print(f"Невозможно декодировать файл .desktop (неподдерживаемая кодировка) при попытке получить имя префикса: {desktop_file}")
|
||||
except Exception as e:
|
||||
print(f"Error getting prefix name from {desktop_file}: {e}")
|
||||
print(f"Ошибка получения имени префикса из {desktop_file}: {e}")
|
||||
return None
|
||||
|
||||
def _get_current_app_title(self):
|
||||
@@ -3648,13 +3825,14 @@ class WineHelperGUI(QMainWindow):
|
||||
prefix_name = self._get_prefix_name_for_selected_app()
|
||||
|
||||
if not prefix_name:
|
||||
QMessageBox.warning(self, "Менеджер Winetricks",
|
||||
"Не удалось определить префикс. Выберите установленное приложение или создайте новый префикс.")
|
||||
error_msg = "Не удалось определить префикс. Выберите установленное приложение или создайте новый префикс."
|
||||
ErrorReporter.show_error(self, "Менеджер Winetricks", error_msg)
|
||||
return
|
||||
|
||||
prefix_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name)
|
||||
if not os.path.isdir(prefix_path):
|
||||
QMessageBox.critical(self, "Ошибка", f"Каталог префикса не найден:\n{prefix_path}")
|
||||
error_msg = f"Каталог префикса не найден:\n{prefix_path}"
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
return
|
||||
|
||||
winetricks_path = Var.WH_WINETRICKS
|
||||
@@ -3678,6 +3856,12 @@ class WineHelperGUI(QMainWindow):
|
||||
if value:
|
||||
wh_wine_use = value
|
||||
break
|
||||
except FileNotFoundError:
|
||||
print(f"Файл last.conf не найден при попытке получить версию Wine: {last_conf_path}")
|
||||
except PermissionError:
|
||||
print(f"Нет доступа к файлу last.conf при попытке получить версию Wine: {last_conf_path}")
|
||||
except UnicodeDecodeError:
|
||||
print(f"Невозможно декодировать файл last.conf (неподдерживаемая кодировка) при попытке получить версию Wine: {last_conf_path}")
|
||||
except Exception as e:
|
||||
print(f"Предупреждение: не удалось прочитать или обработать {last_conf_path}: {e}")
|
||||
|
||||
@@ -3698,7 +3882,8 @@ class WineHelperGUI(QMainWindow):
|
||||
|
||||
last_conf_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name, "last.conf")
|
||||
if not os.path.exists(last_conf_path):
|
||||
QMessageBox.warning(self, "Ошибка", f"Файл last.conf не найден для префикса '{prefix_name}'.")
|
||||
error_msg = f"Файл last.conf не найден для префикса '{prefix_name}'."
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
return
|
||||
|
||||
new_value = "1" if is_enabled else "0"
|
||||
@@ -3724,8 +3909,14 @@ class WineHelperGUI(QMainWindow):
|
||||
# Обновляем информационную панель, чтобы отразить изменения
|
||||
self.update_prefix_info_display(prefix_name)
|
||||
|
||||
except IOError as e:
|
||||
QMessageBox.critical(self, "Ошибка записи", f"Не удалось обновить файл last.conf:\n{e}")
|
||||
except FileNotFoundError:
|
||||
QMessageBox.critical(self, "Ошибка", f"Файл last.conf не найден для префикса '{prefix_name}':\n{last_conf_path}")
|
||||
except PermissionError:
|
||||
QMessageBox.critical(self, "Ошибка", f"Нет доступа к файлу last.conf для записи:\n{last_conf_path}")
|
||||
except UnicodeDecodeError:
|
||||
QMessageBox.critical(self, "Ошибка", f"Невозможно декодировать файл last.conf (неподдерживаемая кодировка):\n{last_conf_path}")
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Ошибка записи", f"Не удалось обновить файл last.conf:\n{str(e)}")
|
||||
|
||||
def _run_wine_util(self, util_name, prefix_name=None):
|
||||
"""Запускает стандартную утилиту Wine для выбранного префикса."""
|
||||
@@ -3733,13 +3924,14 @@ class WineHelperGUI(QMainWindow):
|
||||
prefix_name = self._get_prefix_name_for_selected_app()
|
||||
|
||||
if not prefix_name:
|
||||
QMessageBox.warning(self, "Ошибка",
|
||||
"Не удалось определить префикс. Выберите установленное приложение или создайте новый префикс.")
|
||||
error_msg = "Не удалось определить префикс. Выберите установленное приложение или создайте новый префикс."
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
return
|
||||
|
||||
prefix_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name)
|
||||
if not os.path.isdir(prefix_path):
|
||||
QMessageBox.critical(self, "Ошибка", f"Каталог префикса не найден:\n{prefix_path}")
|
||||
error_msg = f"Каталог префикса не найден:\n{prefix_path}"
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
return
|
||||
|
||||
wine_executable = self._get_wine_executable_for_prefix(prefix_name)
|
||||
@@ -3754,23 +3946,35 @@ class WineHelperGUI(QMainWindow):
|
||||
# x-terminal-emulator - стандартный способ вызова терминала по умолчанию
|
||||
subprocess.Popen(['x-terminal-emulator', '-e', terminal_command])
|
||||
except FileNotFoundError:
|
||||
QMessageBox.critical(self, "Ошибка", "Не удалось найти `x-terminal-emulator`.\nУбедитесь, что у вас установлен терминал по умолчанию (например, mate-terminal или xterm).")
|
||||
error_msg = "Не удалось найти `x-terminal-emulator`.\nУбедитесь, что у вас установлен терминал по умолчанию (например, mate-terminal или xterm)."
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
except PermissionError:
|
||||
error_msg = f"Нет доступа к терминалу для запуска команды:\n{terminal_command}"
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Ошибка", f"Не удалось запустить терминал: {e}")
|
||||
error_msg = f"Не удалось запустить терминал: {e}"
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg, traceback.format_exc())
|
||||
return
|
||||
|
||||
# Для остальных утилит
|
||||
command = [wine_executable, util_name]
|
||||
try:
|
||||
subprocess.Popen(command, env=env)
|
||||
except FileNotFoundError:
|
||||
error_msg = f"Файл Wine не найден:\n{wine_executable}"
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
except PermissionError:
|
||||
error_msg = f"Нет доступа к файлу Wine для запуска:\n{wine_executable}"
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Ошибка запуска",
|
||||
f"Не удалось запустить команду:\n{' '.join(command)}\n\nОшибка: {str(e)}")
|
||||
error_msg = f"Не удалось запустить команду:\n{' '.join(command)}\n\nОшибка: {str(e)}"
|
||||
ErrorReporter.show_error(self, "Ошибка запуска", error_msg, traceback.format_exc())
|
||||
|
||||
def toggle_run_stop_app(self):
|
||||
"""Запускает или останавливает выбранное приложение."""
|
||||
if not self.current_selected_app or 'desktop_path' not in self.current_selected_app:
|
||||
QMessageBox.warning(self, "Ошибка", "Сначала выберите приложение.")
|
||||
error_msg = "Сначала выберите приложение."
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
return
|
||||
|
||||
desktop_path = self.current_selected_app['desktop_path']
|
||||
@@ -3847,7 +4051,8 @@ class WineHelperGUI(QMainWindow):
|
||||
def _run_app_launcher(self, debug=False):
|
||||
"""Внутренний метод для запуска приложения (с отладкой или без) с использованием QProcess."""
|
||||
if not self.current_selected_app or 'exec' not in self.current_selected_app:
|
||||
QMessageBox.warning(self, "Ошибка", "Сначала выберите приложение.")
|
||||
error_msg = "Сначала выберите приложение."
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
return
|
||||
|
||||
desktop_path = self.current_selected_app['desktop_path']
|
||||
@@ -4021,14 +4226,16 @@ class WineHelperGUI(QMainWindow):
|
||||
def uninstall_app(self):
|
||||
"""Удаляет выбранное установленное приложение и его префикс"""
|
||||
if not self.current_selected_app or 'desktop_path' not in self.current_selected_app:
|
||||
QMessageBox.warning(self, "Ошибка", "Сначала выберите приложение.")
|
||||
error_msg = "Сначала выберите приложение."
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
return
|
||||
|
||||
app_name = self.current_selected_app.get('name', 'это приложение')
|
||||
prefix_name = self._get_prefix_name_for_selected_app()
|
||||
|
||||
if not prefix_name:
|
||||
QMessageBox.warning(self, "Ошибка", "Не удалось определить префикс для выбранного приложения.")
|
||||
error_msg = "Не удалось определить префикс для выбранного приложения."
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
return
|
||||
|
||||
# Создаем кастомные кнопки
|
||||
@@ -4087,6 +4294,10 @@ class WineHelperGUI(QMainWindow):
|
||||
print(f"Удален префикс: {prefix_path}")
|
||||
else:
|
||||
print(f"Префикс не найден: {prefix_path}")
|
||||
except FileNotFoundError:
|
||||
raise RuntimeError(f"Префикс не найден: {prefix_path}")
|
||||
except PermissionError:
|
||||
raise RuntimeError(f"Нет доступа к префиксу для удаления: {prefix_path}")
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Ошибка удаления префикса: {str(e)}")
|
||||
|
||||
@@ -4115,14 +4326,32 @@ class WineHelperGUI(QMainWindow):
|
||||
]
|
||||
for f in menu_files:
|
||||
if os.path.exists(f):
|
||||
os.remove(f)
|
||||
try:
|
||||
os.remove(f)
|
||||
except FileNotFoundError:
|
||||
print(f"Файл меню не найден для удаления: {f}")
|
||||
except PermissionError:
|
||||
print(f"Нет доступа к файлу меню для удаления: {f}")
|
||||
except Exception as e:
|
||||
print(f"Ошибка удаления файла меню {f}: {str(e)}")
|
||||
except FileNotFoundError:
|
||||
print(f"Директория меню не найдена для удаления: {menu_dir}")
|
||||
except PermissionError:
|
||||
print(f"Нет доступа к директории меню для удаления: {menu_dir}")
|
||||
except OSError as e:
|
||||
print(f"Ошибка удаления директории меню {menu_dir}: {str(e)}")
|
||||
except Exception as e:
|
||||
print(f"Ошибка удаления пустой категории меню: {str(e)}")
|
||||
|
||||
# Обновляем кэш desktop файлов
|
||||
try:
|
||||
subprocess.run(
|
||||
["update-desktop-database", os.path.join(os.path.expanduser("~"), ".local/share/applications")])
|
||||
result = subprocess.run(
|
||||
["update-desktop-database", os.path.join(os.path.expanduser("~"), ".local/share/applications")],
|
||||
capture_output=True, text=True, check=False)
|
||||
if result.returncode != 0:
|
||||
print(f"Предупреждение: update-desktop-database завершился с кодом {result.returncode}: {result.stderr}")
|
||||
except FileNotFoundError:
|
||||
print("Предупреждение: команда update-desktop-database не найдена")
|
||||
except Exception as e:
|
||||
print(f"Ошибка обновления кэша desktop файлов: {str(e)}")
|
||||
|
||||
@@ -4146,11 +4375,11 @@ class WineHelperGUI(QMainWindow):
|
||||
self._reset_info_panel_to_default("Установленные")
|
||||
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Ошибка",
|
||||
f"Не удалось удалить приложение: {str(e)}\n\n"
|
||||
f"Desktop файл: {self.current_selected_app.get('desktop_path', 'не определен')}\n"
|
||||
f"Префикс: {prefix_name}\n"
|
||||
f"Путь к префиксу: {prefix_path if 'prefix_path' in locals() else 'не определен'}")
|
||||
error_msg = f"Не удалось удалить приложение: {str(e)}\n\n" \
|
||||
f"Desktop файл: {self.current_selected_app.get('desktop_path', 'не определен')}\n" \
|
||||
f"Префикс: {prefix_name}\n" \
|
||||
f"Путь к префиксу: {prefix_path if 'prefix_path' in locals() else 'не определен'}"
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg, traceback.format_exc())
|
||||
def _filter_buttons_in_grid(self, search_text, button_list, grid_layout):
|
||||
"""Общий метод для фильтрации кнопок и перестроения сетки (helper)."""
|
||||
search_text_lower = search_text.lower()
|
||||
@@ -4259,7 +4488,7 @@ class WineHelperGUI(QMainWindow):
|
||||
try:
|
||||
license_file_path = Var.LICENSE_AGREEMENT_FILE
|
||||
if not license_file_path or not os.path.exists(license_file_path):
|
||||
raise FileNotFoundError
|
||||
raise FileNotFoundError("Файл лицензионного соглашения не найден")
|
||||
|
||||
with open(license_file_path, 'r', encoding='utf-8') as f:
|
||||
license_content = f.read()
|
||||
@@ -4268,8 +4497,12 @@ class WineHelperGUI(QMainWindow):
|
||||
license_text.setHtml(f"""
|
||||
<pre style="font-family: sans-serif; font-size: 10pt; white-space: pre-wrap; word-wrap: break-word;">{escaped_license_content}</pre>
|
||||
""")
|
||||
except (FileNotFoundError, TypeError):
|
||||
except FileNotFoundError:
|
||||
license_text.setHtml(f'<h3>Лицензионные соглашения</h3><p>Не удалось загрузить файл лицензионного соглашения по пути:<br>{Var.LICENSE_AGREEMENT_FILE}</p>')
|
||||
except PermissionError:
|
||||
license_text.setHtml(f'<h3>Лицензионные соглашения</h3><p>Нет доступа к файлу лицензионного соглашения:<br>{Var.LICENSE_AGREEMENT_FILE}</p>')
|
||||
except UnicodeDecodeError:
|
||||
license_text.setHtml(f'<h3>Лицензионные соглашения</h3><p>Невозможно декодировать файл лицензионного соглашения (неподдерживаемая кодировка):<br>{Var.LICENSE_AGREEMENT_FILE}</p>')
|
||||
except Exception as e:
|
||||
license_text.setHtml(f'<h3>Лицензионные соглашения</h3><p>Произошла ошибка при чтении файла лицензии:<br>{str(e)}</p>')
|
||||
|
||||
@@ -4298,11 +4531,13 @@ class WineHelperGUI(QMainWindow):
|
||||
def install_current_script(self):
|
||||
"""Устанавливает текущий выбранный скрипт"""
|
||||
if not self.current_script:
|
||||
QMessageBox.warning(self, "Ошибка", "Не выбрана программа для установки")
|
||||
error_msg = "Не выбрана программа для установки"
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
return
|
||||
|
||||
if self.current_script in self.manualinstall_scripts and not self.install_path_edit.text().strip():
|
||||
QMessageBox.warning(self, "Ошибка", "Укажите путь к установочному файлу")
|
||||
error_msg = "Укажите путь к установочному файлу"
|
||||
ErrorReporter.show_error(self, "Ошибка", error_msg)
|
||||
return
|
||||
|
||||
if not self._show_license_agreement_dialog():
|
||||
@@ -4364,10 +4599,12 @@ class WineHelperGUI(QMainWindow):
|
||||
self.current_script)
|
||||
|
||||
if not os.path.exists(winehelper_path):
|
||||
QMessageBox.critical(self.install_dialog, "Ошибка", f"winehelper не найден по пути:\n{winehelper_path}")
|
||||
error_msg = f"winehelper не найден по пути:\n{winehelper_path}"
|
||||
ErrorReporter.show_error(self.install_dialog, "Ошибка", error_msg)
|
||||
return
|
||||
if not os.path.exists(script_path):
|
||||
QMessageBox.critical(self.install_dialog, "Ошибка", f"Скрипт установки не найден:\n{script_path}")
|
||||
error_msg = f"Скрипт установки не найден:\n{script_path}"
|
||||
ErrorReporter.show_error(self.install_dialog, "Ошибка", error_msg)
|
||||
return
|
||||
|
||||
if self.current_script in self.manualinstall_scripts:
|
||||
@@ -4375,6 +4612,14 @@ class WineHelperGUI(QMainWindow):
|
||||
if not install_file:
|
||||
QMessageBox.critical(self.install_dialog, "Ошибка", "Не указан путь к установочному файлу")
|
||||
return
|
||||
if not os.path.exists(install_file):
|
||||
error_msg = f"Установочный файл не найден:\n{install_file}"
|
||||
ErrorReporter.show_error(self.install_dialog, "Ошибка", error_msg)
|
||||
return
|
||||
if not os.access(install_file, os.R_OK):
|
||||
error_msg = f"Нет доступа для чтения к установочному файлу:\n{install_file}"
|
||||
ErrorReporter.show_error(self.install_dialog, "Ошибка", error_msg)
|
||||
return
|
||||
QTimer.singleShot(100, lambda: self._start_installation(winehelper_path, script_path, install_file))
|
||||
else:
|
||||
QTimer.singleShot(100, lambda: self._start_installation(winehelper_path, script_path))
|
||||
@@ -4407,9 +4652,25 @@ class WineHelperGUI(QMainWindow):
|
||||
if not self.install_process.waitForStarted(3000):
|
||||
raise RuntimeError("Не удалось запустить процесс установки")
|
||||
self.append_log("Процесс установки запущен...")
|
||||
except FileNotFoundError:
|
||||
error_msg = f"Файл winehelper не найден: {winehelper_path}"
|
||||
self.append_log(f"\n=== ОШИБКА: {error_msg} ===", is_error=True)
|
||||
ErrorReporter.show_error(self.install_dialog, "Ошибка запуска установки", error_msg)
|
||||
self.cleanup_process()
|
||||
except PermissionError:
|
||||
error_msg = f"Нет доступа к файлу winehelper: {winehelper_path}"
|
||||
self.append_log(f"\n=== ОШИБКА: {error_msg} ===", is_error=True)
|
||||
ErrorReporter.show_error(self.install_dialog, "Ошибка запуска установки", error_msg)
|
||||
self.cleanup_process()
|
||||
except OSError as e:
|
||||
error_msg = f"Ошибка операционной системы при запуске установки: {str(e)}"
|
||||
self.append_log(f"\n=== ОШИБКА: {error_msg} ===", is_error=True)
|
||||
ErrorReporter.show_error(self.install_dialog, "Ошибка запуска установки", error_msg, str(e))
|
||||
self.cleanup_process()
|
||||
except Exception as e:
|
||||
self.append_log(f"\n=== ОШИБКА: {str(e)} ===", is_error=True)
|
||||
QMessageBox.critical(self.install_dialog, "Ошибка", f"Не удалось запустить установку:\n{str(e)}")
|
||||
error_msg = f"Не удалось запустить установку: {str(e)}"
|
||||
self.append_log(f"\n=== ОШИБКА: {error_msg} ===", is_error=True)
|
||||
ErrorReporter.show_error(self.install_dialog, "Ошибка запуска установки", error_msg, traceback.format_exc())
|
||||
self.cleanup_process()
|
||||
|
||||
def _append_to_log(self, log_widget, text, is_error=False, add_newline=True):
|
||||
@@ -4706,7 +4967,15 @@ class WineHelperGUI(QMainWindow):
|
||||
process.setProcessEnvironment(env)
|
||||
|
||||
log_output.append(f"Выполнение: {shlex.quote(command)} {' '.join(shlex.quote(a) for a in args)}")
|
||||
process.start(command, args)
|
||||
|
||||
# Check if the command exists before starting the process
|
||||
if not os.path.exists(command):
|
||||
error_msg = f"Файл команды не найден: {command}"
|
||||
log_output.append(f"\n=== ОШИБКА: {error_msg} ===")
|
||||
ErrorReporter.log_error(error_msg)
|
||||
process = None # Prevent starting a non-existent command
|
||||
else:
|
||||
process.start(command, args)
|
||||
|
||||
return dialog, process, log_output, close_button
|
||||
|
||||
@@ -4730,6 +4999,14 @@ class WineHelperGUI(QMainWindow):
|
||||
|
||||
def _run_simple_command(self, command, args=None):
|
||||
"""Запускает простую команду winehelper и выводит лог."""
|
||||
# Check if the winehelper executable exists before starting the process
|
||||
if not os.path.exists(self.winehelper_path):
|
||||
error_msg = f"Файл winehelper не найден: {self.winehelper_path}"
|
||||
if hasattr(self, 'command_log_output') and self.command_log_output:
|
||||
self.command_log_output.append(f"\n=== ОШИБКА: {error_msg} ===")
|
||||
ErrorReporter.log_error(error_msg)
|
||||
return
|
||||
|
||||
self.command_process = QProcess(self.command_dialog)
|
||||
self.command_process.setProcessChannelMode(QProcess.MergedChannels)
|
||||
self.command_process.readyReadStandardOutput.connect(self._handle_command_output)
|
||||
@@ -4749,7 +5026,9 @@ class WineHelperGUI(QMainWindow):
|
||||
if exit_code == 0:
|
||||
log_output.append(f"\n=== Команда успешно завершена ===")
|
||||
else:
|
||||
log_output.append(f"\n=== Ошибка выполнения (код: {exit_code}) ===")
|
||||
error_msg = f"Ошибка выполнения (код: {exit_code})"
|
||||
log_output.append(f"\n=== {error_msg} ===")
|
||||
ErrorReporter.log_error(f"Команда завершилась с кодом ошибки {exit_code}")
|
||||
log_output.ensureCursorVisible()
|
||||
|
||||
if process:
|
||||
|
||||
Reference in New Issue
Block a user