diff --git a/winehelper_gui.py b/winehelper_gui.py index 9ade5cb..08f4c47 100644 --- a/winehelper_gui.py +++ b/winehelper_gui.py @@ -1268,8 +1268,14 @@ class WineHelperGUI(QMainWindow): self.icon_animators = {} self.previous_tab_index = 0 self.selected_wine_version_value = None - self.last_created_prefix_name = None - self.last_created_prefix_info = None + self.created_prefixes_info = {} # Хранит информацию о префиксах, созданных на вкладке + self.current_managed_prefix_name = None # Имя префикса, выбранного в выпадающем списке + self.pending_prefix_info = None # Временное хранилище информации о создаваемом префиксе + + # Добавим путь к файлу состояния + self.config_dir = os.path.join(os.path.expanduser("~"), ".config", "winehelper") + os.makedirs(self.config_dir, exist_ok=True) + self.state_file = os.path.join(self.config_dir, "gui_state.json") # State for command dialog log processing (specifically for prefix creation) self.command_output_buffer = "" @@ -1306,6 +1312,9 @@ class WineHelperGUI(QMainWindow): self.create_prefix_tab() self.create_help_tab() + # Загружаем состояние после создания всех виджетов + self._load_state() + # Инициализируем состояние, которое будет использоваться для логов self._reset_log_state() @@ -1819,18 +1828,19 @@ class WineHelperGUI(QMainWindow): self.prefix_name_edit.setPlaceholderText("Например: my_prefix") form_layout.addRow("Имя нового префикса:", self.prefix_name_edit) - self.arch_groupbox = QGroupBox("Архитектура") - arch_layout = QHBoxLayout() + arch_widget = QWidget() + arch_layout = QHBoxLayout(arch_widget) + arch_layout.setContentsMargins(0, 0, 0, 0) self.arch_win32_radio = QRadioButton("32-bit") self.arch_win64_radio = QRadioButton("64-bit") self.arch_win64_radio.setChecked(True) arch_layout.addWidget(self.arch_win32_radio) arch_layout.addWidget(self.arch_win64_radio) - self.arch_groupbox.setLayout(arch_layout) - form_layout.addRow("Разрядность:", self.arch_groupbox) + form_layout.addRow("Разрядность:", arch_widget) - self.type_groupbox = QGroupBox("Тип префикса") - type_layout = QHBoxLayout() + type_widget = QWidget() + type_layout = QHBoxLayout(type_widget) + type_layout.setContentsMargins(0, 0, 0, 0) self.type_clean_radio = QRadioButton("Чистый") self.type_clean_radio.setToolTip("Создает пустой префикс Wine без каких-либо дополнительных компонентов.") self.type_recommended_radio = QRadioButton("С рекомендуемыми библиотеками") @@ -1839,8 +1849,7 @@ class WineHelperGUI(QMainWindow): self.type_clean_radio.setChecked(True) type_layout.addWidget(self.type_clean_radio) type_layout.addWidget(self.type_recommended_radio) - self.type_groupbox.setLayout(type_layout) - form_layout.addRow("Наполнение:", self.type_groupbox) + form_layout.addRow("Наполнение:", type_widget) self.wine_version_edit = QLineEdit() self.wine_version_edit.setReadOnly(True) @@ -1854,63 +1863,6 @@ class WineHelperGUI(QMainWindow): version_layout.addWidget(select_version_button) form_layout.addRow("Версия Wine/Proton:", version_layout) - # --- GroupBox for managing the created prefix --- - self.prefix_management_groupbox = QGroupBox("Управление префиксом") - self.prefix_management_groupbox.setEnabled(False) # Disabled by default - management_layout = QGridLayout(self.prefix_management_groupbox) - management_layout.setSpacing(5) - - # --- Left side: Buttons --- - self.prefix_winetricks_button = QPushButton("Менеджер компонентов") - self.prefix_winetricks_button.clicked.connect( - lambda: self.open_winetricks_manager(prefix_name=self.last_created_prefix_name)) - self.prefix_winetricks_button.setToolTip( - "Установка компонентов, библиотек и шрифтов в префикс с помощью Winetricks.") - management_layout.addWidget(self.prefix_winetricks_button, 0, 0) - - self.prefix_winecfg_button = QPushButton("Редактор настроек") - self.prefix_winecfg_button.clicked.connect( - lambda: self._run_wine_util('winecfg', prefix_name=self.last_created_prefix_name)) - self.prefix_winecfg_button.setToolTip( - "Запуск утилиты winecfg для настройки параметров Wine (версия Windows, диски, аудио и т.д.).") - management_layout.addWidget(self.prefix_winecfg_button, 0, 1) - - self.prefix_regedit_button = QPushButton("Редактор реестра") - self.prefix_regedit_button.clicked.connect( - lambda: self._run_wine_util('regedit', prefix_name=self.last_created_prefix_name)) - self.prefix_regedit_button.setToolTip( - "Запуск редактора реестра Wine (regedit) для просмотра и изменения ключей реестра в префиксе.") - management_layout.addWidget(self.prefix_regedit_button, 1, 0) - - self.prefix_uninstaller_button = QPushButton("Удаление программ") - self.prefix_uninstaller_button.clicked.connect( - lambda: self._run_wine_util('uninstaller', prefix_name=self.last_created_prefix_name)) - self.prefix_uninstaller_button.setToolTip( - "Запуск стандартного деинсталлятора Wine для удаления установленных в префикс Windows-программ.") - management_layout.addWidget(self.prefix_uninstaller_button, 1, 1) - - self.prefix_cmd_button = QPushButton("Командная строка") - self.prefix_cmd_button.clicked.connect(lambda: self._run_wine_util('cmd', prefix_name=self.last_created_prefix_name)) - self.prefix_cmd_button.setToolTip("Запуск командной строки (cmd) в окружении выбранного префикса.") - management_layout.addWidget(self.prefix_cmd_button, 2, 0) - - self.prefix_winefile_button = QPushButton("Файловый менеджер") - self.prefix_winefile_button.clicked.connect( - lambda: self._run_wine_util('winefile', prefix_name=self.last_created_prefix_name)) - self.prefix_winefile_button.setToolTip("Запуск файлового менеджера Wine (winefile) для просмотра файлов внутри префикса.") - management_layout.addWidget(self.prefix_winefile_button, 2, 1) - - # --- Right side: Info display --- - self.prefix_info_display = QTextBrowser() - self.prefix_info_display.setReadOnly(True) - self.prefix_info_display.setFrameStyle(QFrame.StyledPanel) - management_layout.addWidget(self.prefix_info_display, 0, 2, 3, 1) - - # Устанавливаем растяжение колонок, чтобы область кнопок и область информации были примерно равны - management_layout.setColumnStretch(0, 1) - management_layout.setColumnStretch(1, 1) - management_layout.setColumnStretch(2, 2) - self.create_prefix_button = QPushButton("Создать префикс") self.create_prefix_button.setFont(QFont('Arial', 12, QFont.Bold)) self.create_prefix_button.setStyleSheet("background-color: #0078d7; color: white;") @@ -1919,7 +1871,75 @@ class WineHelperGUI(QMainWindow): layout.addLayout(form_layout) layout.addWidget(self.create_prefix_button) - layout.addWidget(self.prefix_management_groupbox) + + # --- Контейнер для выбора и управления созданными префиксами --- + self.management_container_groupbox = QGroupBox("Управление созданными префиксами") + self.management_container_groupbox.setVisible(False) # Скрыт, пока нет префиксов + container_layout = QVBoxLayout(self.management_container_groupbox) + + self.created_prefix_selector = QComboBox() + self.created_prefix_selector.setPlaceholderText("Выберите префикс для управления") + self.created_prefix_selector.currentIndexChanged.connect(self.on_created_prefix_selected) + container_layout.addWidget(self.created_prefix_selector) + + # --- GroupBox для управления выбранным префиксом --- + self.prefix_management_groupbox = QGroupBox("Управление") # Заголовок будет меняться + self.prefix_management_groupbox.setEnabled(False) + management_layout = QGridLayout(self.prefix_management_groupbox) + management_layout.setSpacing(5) + + # --- Левая сторона: Кнопки --- + self.prefix_winetricks_button = QPushButton("Менеджер компонентов") + self.prefix_winetricks_button.clicked.connect( + lambda: self.open_winetricks_manager(prefix_name=self.current_managed_prefix_name)) + self.prefix_winetricks_button.setToolTip( + "Установка компонентов, библиотек и шрифтов в префикс с помощью Winetricks.") + management_layout.addWidget(self.prefix_winetricks_button, 0, 0) + + self.prefix_winecfg_button = QPushButton("Редактор настроек") + self.prefix_winecfg_button.clicked.connect( + lambda: self._run_wine_util('winecfg', prefix_name=self.current_managed_prefix_name)) + self.prefix_winecfg_button.setToolTip( + "Запуск утилиты winecfg для настройки параметров Wine (версия Windows, диски, аудио и т.д.).") + management_layout.addWidget(self.prefix_winecfg_button, 0, 1) + + self.prefix_regedit_button = QPushButton("Редактор реестра") + self.prefix_regedit_button.clicked.connect( + lambda: self._run_wine_util('regedit', prefix_name=self.current_managed_prefix_name)) + self.prefix_regedit_button.setToolTip( + "Запуск редактора реестра Wine (regedit) для просмотра и изменения ключей реестра в префиксе.") + management_layout.addWidget(self.prefix_regedit_button, 1, 0) + + self.prefix_uninstaller_button = QPushButton("Удаление программ") + self.prefix_uninstaller_button.clicked.connect( + lambda: self._run_wine_util('uninstaller', prefix_name=self.current_managed_prefix_name)) + self.prefix_uninstaller_button.setToolTip( + "Запуск стандартного деинсталлятора Wine для удаления установленных в префикс Windows-программ.") + management_layout.addWidget(self.prefix_uninstaller_button, 1, 1) + + self.prefix_cmd_button = QPushButton("Командная строка") + self.prefix_cmd_button.clicked.connect(lambda: self._run_wine_util('cmd', prefix_name=self.current_managed_prefix_name)) + self.prefix_cmd_button.setToolTip("Запуск командной строки (cmd) в окружении выбранного префикса.") + management_layout.addWidget(self.prefix_cmd_button, 2, 0) + + self.prefix_winefile_button = QPushButton("Файловый менеджер") + self.prefix_winefile_button.clicked.connect( + lambda: self._run_wine_util('winefile', prefix_name=self.current_managed_prefix_name)) + self.prefix_winefile_button.setToolTip("Запуск файлового менеджера Wine (winefile) для просмотра файлов внутри префикса.") + management_layout.addWidget(self.prefix_winefile_button, 2, 1) + + # --- Правая сторона: Информационный блок --- + self.prefix_info_display = QTextBrowser() + self.prefix_info_display.setReadOnly(True) + self.prefix_info_display.setFrameStyle(QFrame.StyledPanel) + management_layout.addWidget(self.prefix_info_display, 0, 2, 3, 1) + + management_layout.setColumnStretch(0, 1) + management_layout.setColumnStretch(1, 1) + management_layout.setColumnStretch(2, 2) + + container_layout.addWidget(self.prefix_management_groupbox) + layout.addWidget(self.management_container_groupbox) layout.addStretch() self.add_tab(self.prefix_tab, "Создать префикс") @@ -1928,22 +1948,92 @@ class WineHelperGUI(QMainWindow): self.prefix_name_edit.textChanged.connect(self.on_prefix_name_edited) self.wine_version_edit.textChanged.connect(self.update_create_prefix_button_state) + def _load_state(self): + """Загружает последнее состояние GUI из файла.""" + if not os.path.exists(self.state_file): + return + try: + with open(self.state_file, 'r', encoding='utf-8') as f: + state = json.load(f) + + loaded_prefixes = state.get('created_prefixes_info', {}) + if not loaded_prefixes: + return + + # Блокируем сигналы, чтобы избежать преждевременного срабатывания + self.created_prefix_selector.blockSignals(True) + self.created_prefix_selector.clear() + self.created_prefixes_info.clear() + + for prefix_name, prefix_info in loaded_prefixes.items(): + prefix_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name) + if os.path.isdir(prefix_path): + self.created_prefixes_info[prefix_name] = prefix_info + self.created_prefix_selector.addItem(prefix_name) + + self.created_prefix_selector.blockSignals(False) + + if self.created_prefix_selector.count() > 0: + self.management_container_groupbox.setVisible(True) + last_managed = state.get('current_managed_prefix_name') + index = self.created_prefix_selector.findText(last_managed) + if index != -1: + self.created_prefix_selector.setCurrentIndex(index) + else: + self.created_prefix_selector.setCurrentIndex(0) # Выбираем первый, если предыдущий не найден + else: + self.management_container_groupbox.setVisible(False) + + except (IOError, json.JSONDecodeError, TypeError) as e: + print(f"Предупреждение: не удалось загрузить состояние GUI: {e}") + + def _save_state(self): + """Сохраняет текущее состояние GUI в файл.""" + state = { + 'created_prefixes_info': self.created_prefixes_info, + 'current_managed_prefix_name': self.current_managed_prefix_name + } + try: + with open(self.state_file, 'w', encoding='utf-8') as f: + json.dump(state, f, indent=2, ensure_ascii=False) + except IOError as e: + print(f"Предупреждение: не удалось сохранить состояние GUI: {e}") + + def on_created_prefix_selected(self, index): + """Обрабатывает выбор префикса из выпадающего списка.""" + if index == -1: + self.current_managed_prefix_name = None + self._setup_prefix_management_panel(None) + else: + prefix_name = self.created_prefix_selector.itemText(index) + self.current_managed_prefix_name = prefix_name + self._setup_prefix_management_panel(prefix_name) + self._save_state() + def on_prefix_name_edited(self, text): """Сбрасывает состояние управления префиксом, когда пользователь вводит новое имя.""" - if text and self.prefix_management_groupbox.isEnabled(): + if text: + if self.created_prefix_selector.currentIndex() != -1: + self.created_prefix_selector.setCurrentIndex(-1) + + def _setup_prefix_management_panel(self, prefix_name): + """Настраивает панель управления префиксом на основе текущего состояния.""" + if prefix_name and prefix_name in self.created_prefixes_info: + self.prefix_management_groupbox.setTitle(f"Управление «{prefix_name}»") + self.prefix_management_groupbox.setEnabled(True) + self.update_prefix_info_display(prefix_name) + else: + self.prefix_management_groupbox.setTitle("Управление") self.prefix_management_groupbox.setEnabled(False) - self.prefix_management_groupbox.setTitle("Управление префиксом") - self.last_created_prefix_name = None - self.last_created_prefix_info = None self.prefix_info_display.clear() - def update_prefix_info_display(self): + def update_prefix_info_display(self, prefix_name): """Обновляет информационный блок для созданного префикса.""" - if not self.last_created_prefix_info: + info = self.created_prefixes_info.get(prefix_name) + if not info: self.prefix_info_display.clear() return - info = self.last_created_prefix_info html_content = f"""

Имя: {html.escape(info['name'])}
@@ -2083,12 +2173,9 @@ class WineHelperGUI(QMainWindow): if not self._show_license_agreement_dialog(): return - # Сбрасываем состояние управления предыдущим созданным префиксом - self.last_created_prefix_name = None - self.last_created_prefix_info = None - self.prefix_info_display.clear() - self.prefix_management_groupbox.setEnabled(False) - self.prefix_management_groupbox.setTitle("Управление префиксом") + # Сбрасываем выбор в выпадающем списке, чтобы панель управления скрылась на время создания + if self.created_prefix_selector.count() > 0: + self.created_prefix_selector.setCurrentIndex(-1) prefix_name = self.prefix_name_edit.text().strip() @@ -2111,7 +2198,7 @@ class WineHelperGUI(QMainWindow): wine_use_display = self.wine_version_edit.text() # Сохраняем информацию для отображения после создания - self.last_created_prefix_info = { + self.pending_prefix_info = { 'name': prefix_name, 'path': prefix_path, 'arch': "32-bit" if wine_arch == "win32" else "64-bit", @@ -2181,14 +2268,25 @@ class WineHelperGUI(QMainWindow): self._handle_command_finished(exit_code, exit_status) if exit_code == 0: - self.last_created_prefix_name = prefix_name - self.prefix_management_groupbox.setTitle(f"Управление префиксом «{prefix_name}»") - self.prefix_management_groupbox.setEnabled(True) - self.update_prefix_info_display() + # Добавляем новый префикс в список и выбираем его + if self.pending_prefix_info: + self.created_prefixes_info[prefix_name] = self.pending_prefix_info + self.pending_prefix_info = None + + if self.created_prefix_selector.findText(prefix_name) == -1: + self.created_prefix_selector.addItem(prefix_name) + + self.created_prefix_selector.setCurrentText(prefix_name) + + if not self.management_container_groupbox.isVisible(): + self.management_container_groupbox.setVisible(True) + + self._save_state() self.prefix_name_edit.clear() self.wine_version_edit.clear() QMessageBox.information(self, "Успех", - f"Префикс '{prefix_name}' успешно создан.\nТеперь вы можете управлять им с помощью кнопок ниже.") + f"Префикс '{prefix_name}' успешно создан.\n" + "Теперь вы можете управлять им, выбрав его из выпадающего списка.") def update_installed_apps(self): """Обновляет список установленных приложений в виде кнопок"""