forked from CastroFidel/winehelper
encapsulation of script parsing logic
This commit is contained in:
@@ -525,7 +525,7 @@ class WinetricksManagerDialog(QDialog):
|
||||
layout.addWidget(search_edit)
|
||||
|
||||
list_widget = QListWidget()
|
||||
list_widget.itemChanged.connect(self._update_ui_state)
|
||||
list_widget.itemChanged.connect(self._on_item_changed)
|
||||
list_widget.currentItemChanged.connect(self._update_ui_state)
|
||||
layout.addWidget(list_widget)
|
||||
|
||||
@@ -651,18 +651,8 @@ class WinetricksManagerDialog(QDialog):
|
||||
item = QListWidgetItem(item_text)
|
||||
item.setData(Qt.UserRole, name)
|
||||
item.setFont(QFont("DejaVu Sans Mono", 10))
|
||||
|
||||
if is_checked:
|
||||
# Если компонент уже установлен, делаем его неинтерактивным,
|
||||
# так как удаление не поддерживается. Переустановка - через отдельную кнопку.
|
||||
item.setFlags(item.flags() & ~Qt.ItemIsUserCheckable)
|
||||
item.setCheckState(Qt.Checked)
|
||||
item.setToolTip("Этот компонент уже установлен. Для переустановки выделите его и нажмите кнопку 'Переустановить'.")
|
||||
else:
|
||||
# Для неустановленных компонентов разрешаем установку через чекбокс.
|
||||
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
||||
item.setCheckState(Qt.Unchecked)
|
||||
|
||||
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
||||
item.setCheckState(Qt.Checked if is_checked else Qt.Unchecked)
|
||||
list_widget.addItem(item)
|
||||
self.initial_states[name] = is_checked
|
||||
|
||||
@@ -728,6 +718,21 @@ class WinetricksManagerDialog(QDialog):
|
||||
self.status_label.setText("Готово.")
|
||||
self._update_ui_state()
|
||||
|
||||
def _on_item_changed(self, item):
|
||||
"""Обрабатывает изменение состояния чекбокса, предотвращая снятие галочки с установленных."""
|
||||
name = item.data(Qt.UserRole)
|
||||
# Если компонент был изначально установлен и пользователь пытается его снять
|
||||
if name in self.initial_states and self.initial_states.get(name) is True:
|
||||
if item.checkState() == Qt.Unchecked:
|
||||
# Блокируем сигналы, чтобы избежать рекурсии, и возвращаем галочку на место.
|
||||
list_widget = item.listWidget()
|
||||
if list_widget:
|
||||
list_widget.blockSignals(True)
|
||||
item.setCheckState(Qt.Checked)
|
||||
if list_widget:
|
||||
list_widget.blockSignals(False)
|
||||
self._update_ui_state()
|
||||
|
||||
def _update_ui_state(self, *args):
|
||||
"""Централизованно обновляет состояние кнопок 'Применить' и 'Переустановить'."""
|
||||
# 1. Проверяем, есть ли изменения в чекбоксах (установка новых или снятие галочек с новых)
|
||||
@@ -919,6 +924,93 @@ class WinetricksManagerDialog(QDialog):
|
||||
self.log_output.append(message)
|
||||
self.log_output.moveCursor(QTextCursor.End)
|
||||
|
||||
class ScriptParser:
|
||||
"""Утилитарный класс для парсинга информации из скриптов установки."""
|
||||
|
||||
@staticmethod
|
||||
def extract_icons_from_script(script_path):
|
||||
"""
|
||||
Извлекает иконку для скрипта.
|
||||
Сначала ищет переменную 'export PROG_ICON=', если не находит,
|
||||
то ищет все вызовы 'create_desktop' и берет иконки из третьего аргумента.
|
||||
Возвращает список имен иконок.
|
||||
"""
|
||||
try:
|
||||
with open(script_path, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
# 1. Приоритет у PROG_ICON
|
||||
for line in lines:
|
||||
if line.strip().startswith('export PROG_ICON='):
|
||||
icon_name = line.split('=', 1)[1].strip().strip('"\'')
|
||||
if icon_name:
|
||||
return [icon_name]
|
||||
|
||||
# 2. Если PROG_ICON не найден, ищем все вызовы create_desktop
|
||||
icon_names = []
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
# Пропускаем закомментированные строки и пустые строки
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
|
||||
if 'create_desktop' in line:
|
||||
try:
|
||||
parts = shlex.split(line)
|
||||
# Ищем все вхождения, а не только первое
|
||||
for i, part in enumerate(parts):
|
||||
if part == 'create_desktop':
|
||||
if len(parts) > i + 3:
|
||||
icon_name = parts[i + 3]
|
||||
if icon_name:
|
||||
icon_names.append(icon_name)
|
||||
except (ValueError, IndexError):
|
||||
continue
|
||||
return icon_names
|
||||
except Exception as e:
|
||||
print(f"Ошибка чтения файла для извлечения иконки: {str(e)}")
|
||||
return []
|
||||
|
||||
@staticmethod
|
||||
def extract_prog_name_from_script(script_path):
|
||||
"""Извлекает имя программы из строки PROG_NAME= в скрипте"""
|
||||
try:
|
||||
with open(script_path, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
if line.strip().startswith(('export PROG_NAME=', 'PROG_NAME=')):
|
||||
name = line.split('=', 1)[1].strip().strip('"\'')
|
||||
if name:
|
||||
return name
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Ошибка чтения файла для извлечения PROG_NAME: {str(e)}")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def extract_prog_url_from_script(script_path):
|
||||
"""Извлекает URL из строки export PROG_URL= в скрипте"""
|
||||
try:
|
||||
with open(script_path, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
if line.startswith('export PROG_URL='):
|
||||
return line.replace('export PROG_URL=', '').strip().strip('"\'')
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Ошибка чтения файла для извлечения PROG_URL: {str(e)}")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def extract_info_ru(script_path):
|
||||
"""Извлекает информацию из строки # info_ru: в скрипте"""
|
||||
try:
|
||||
with open(script_path, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
if line.startswith('# info_ru:'):
|
||||
return line.replace('# info_ru:', '').strip()
|
||||
return "Описание отсутствует"
|
||||
except Exception as e:
|
||||
return f"Ошибка чтения файла: {str(e)}"
|
||||
|
||||
class WineHelperGUI(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
@@ -1235,77 +1327,6 @@ class WineHelperGUI(QMainWindow):
|
||||
if file_path:
|
||||
self.install_path_edit.setText(file_path)
|
||||
|
||||
def extract_icons_from_script(self, script_path):
|
||||
"""
|
||||
Извлекает иконку для скрипта.
|
||||
Сначала ищет переменную 'export PROG_ICON=', если не находит,
|
||||
то ищет все вызовы 'create_desktop' и берет иконки из третьего аргумента.
|
||||
Возвращает список имен иконок.
|
||||
"""
|
||||
try:
|
||||
with open(script_path, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
# 1. Приоритет у PROG_ICON
|
||||
for line in lines:
|
||||
if line.strip().startswith('export PROG_ICON='):
|
||||
icon_name = line.split('=', 1)[1].strip().strip('"\'')
|
||||
if icon_name:
|
||||
return [icon_name]
|
||||
|
||||
# 2. Если PROG_ICON не найден, ищем все вызовы create_desktop
|
||||
icon_names = []
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
# Пропускаем закомментированные строки и пустые строки
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
|
||||
if 'create_desktop' in line:
|
||||
try:
|
||||
parts = shlex.split(line)
|
||||
# Ищем все вхождения, а не только первое
|
||||
for i, part in enumerate(parts):
|
||||
if part == 'create_desktop':
|
||||
if len(parts) > i + 3:
|
||||
icon_name = parts[i + 3]
|
||||
if icon_name:
|
||||
icon_names.append(icon_name)
|
||||
except (ValueError, IndexError):
|
||||
continue
|
||||
return icon_names
|
||||
except Exception as e:
|
||||
print(f"Ошибка чтения файла для извлечения иконки: {str(e)}")
|
||||
return []
|
||||
|
||||
def extract_prog_name_from_script(self, script_path):
|
||||
"""Извлекает имя программы из строки PROG_NAME= в скрипте"""
|
||||
try:
|
||||
with open(script_path, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
# Ищем строку, которая начинается с PROG_NAME= или export PROG_NAME=
|
||||
if line.strip().startswith(('export PROG_NAME=', 'PROG_NAME=')):
|
||||
# Отделяем имя переменной от значения и убираем кавычки
|
||||
name = line.split('=', 1)[1].strip().strip('"\'')
|
||||
if name:
|
||||
return name
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Ошибка чтения файла для извлечения PROG_NAME: {str(e)}")
|
||||
return None
|
||||
|
||||
def extract_prog_url_from_script(self, script_path):
|
||||
"""Извлекает URL из строки export PROG_URL= в скрипте"""
|
||||
try:
|
||||
with open(script_path, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
if line.startswith('export PROG_URL='):
|
||||
return line.replace('export PROG_URL=', '').strip().strip('"\'')
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Ошибка чтения файла для извлечения PROG_URL: {str(e)}")
|
||||
return None
|
||||
|
||||
def _start_icon_fade_animation(self, button):
|
||||
"""Запускает анимацию плавного перехода для иконки на кнопке с помощью QPropertyAnimation."""
|
||||
if button not in self.icon_animators:
|
||||
@@ -1426,13 +1447,13 @@ class WineHelperGUI(QMainWindow):
|
||||
button_index = 0
|
||||
for script in scripts_list:
|
||||
script_path = os.path.join(Var.DATA_PATH, script_folder, script)
|
||||
prog_name = self.extract_prog_name_from_script(script_path)
|
||||
prog_name = ScriptParser.extract_prog_name_from_script(script_path)
|
||||
|
||||
# Создаем кнопку, только если для скрипта указано имя программы
|
||||
if not prog_name:
|
||||
continue
|
||||
|
||||
icon_names = self.extract_icons_from_script(script_path)
|
||||
icon_names = ScriptParser.extract_icons_from_script(script_path)
|
||||
icon_paths = [os.path.join(Var.DATA_PATH, "image", f"{name}.png") for name in icon_names]
|
||||
btn = self._create_app_button(prog_name, icon_paths, self.BUTTON_LIST_STYLE)
|
||||
|
||||
@@ -2224,17 +2245,6 @@ class WineHelperGUI(QMainWindow):
|
||||
self.installed_search_edit.text(), self.installed_buttons, self.installed_scroll_layout
|
||||
)
|
||||
|
||||
def extract_info_ru(self, script_path):
|
||||
"""Извлекает информацию из строки # info_ru: в скрипте"""
|
||||
try:
|
||||
with open(script_path, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
if line.startswith('# info_ru:'):
|
||||
return line.replace('# info_ru:', '').strip()
|
||||
return "Описание отсутствует"
|
||||
except Exception as e:
|
||||
return f"Ошибка чтения файла: {str(e)}"
|
||||
|
||||
def show_script_info(self, script_name, button_widget):
|
||||
"""Показывает информацию о выбранном скрипте"""
|
||||
self._set_active_button(button_widget)
|
||||
@@ -2264,10 +2274,10 @@ class WineHelperGUI(QMainWindow):
|
||||
QTimer.singleShot(0, lambda: scroll_area.ensureWidgetVisible(frame))
|
||||
|
||||
# Обновляем информацию в правой панели
|
||||
description = self.extract_info_ru(script_path)
|
||||
icon_names = self.extract_icons_from_script(script_path)
|
||||
prog_name = self.extract_prog_name_from_script(script_path)
|
||||
prog_url = self.extract_prog_url_from_script(script_path)
|
||||
description = ScriptParser.extract_info_ru(script_path)
|
||||
icon_names = ScriptParser.extract_icons_from_script(script_path)
|
||||
prog_name = ScriptParser.extract_prog_name_from_script(script_path)
|
||||
prog_url = ScriptParser.extract_prog_url_from_script(script_path)
|
||||
display_name = prog_name if prog_name else script_name
|
||||
self.current_display_name = display_name
|
||||
|
||||
|
Reference in New Issue
Block a user