diff --git a/README.md b/README.md index 38f5f3aa..163a7438 100644 --- a/README.md +++ b/README.md @@ -298,6 +298,13 @@ WineHelper предоставляет доступ к основным инст

Выбранное приложение во вкладке "Установленные"

+Расположения лога запуска программы а также резервной копии префикса можно просмотреть с помощью кнопки **«Открыть папку с логом/резервной копией префикса»** которая появляется автоматически после создания лога или резервной копии. + +
+ +

Кнопка "Открыть папку с логом/резервной копией префикса"

+
+ ### Вкладка «Менеджер префиксов» Эта вкладка предоставляет мощные инструменты для управления префиксами Wine. diff --git a/image/handbook/folder_log_backup.png b/image/handbook/folder_log_backup.png new file mode 100644 index 00000000..b4017429 Binary files /dev/null and b/image/handbook/folder_log_backup.png differ diff --git a/winehelper b/winehelper index fb1fa54a..dbee1ebd 100755 --- a/winehelper +++ b/winehelper @@ -102,7 +102,9 @@ else fi if [[ $WINEDEBUG != "-all" ]] ; then - export LOG_FILE="$HOME/winehelper.log" + log_dir="$HOME/winehelper_backup_log" + mkdir -p "$log_dir" + export LOG_FILE="$log_dir/winehelper.log" date > "$LOG_FILE" print_warning "Включен режим логирования работы WINE." print_warning "Лог будет сохранен по пути: $LOG_FILE" @@ -1773,6 +1775,7 @@ remove_winehelper () { echo " - Все настройки WineHelper" echo " - Все приложения/программы, установленные через WineHelper" echo " - Все ярлыки из меню и с рабочего стола, созданные с помощью WineHelper" + echo " - Все резервные копии и логи, созданные WineHelper" echo "======================================================" if print_confirmation "Продолжить?" ; then echo "----------------------------------------------" @@ -1788,6 +1791,7 @@ remove_winehelper () { # Удаление рабочих каталогов try_remove_dir "$USER_WORK_PATH" + try_remove_dir "$HOME/winehelper_backup_log" # Удаление файлов меню try_remove_dir "$WH_MENU_DIR" @@ -1866,7 +1870,8 @@ backup_prefix() { check_prefix_var local backup_base_dir backup_archive_name backup_dest_path temp_backup_dir temp_prefix_dir temp_users_dir - backup_base_dir="$(xdg-user-dir DESKTOP)" + backup_base_dir="$HOME/winehelper_backup_log" + create_new_dir "$backup_base_dir" backup_archive_name="backup_${PREFIX_NAME}_$(date +%d.%m.%Y-%H.%M.%S).whpack" backup_dest_path="$backup_base_dir/$backup_archive_name" temp_backup_dir="$WH_TMP_DIR/backup_${PREFIX_NAME}_$(date +%d.%m.%Y-%H.%M.%S)" diff --git a/winehelper_gui.py b/winehelper_gui.py index f4e8eec4..d5e1c92e 100644 --- a/winehelper_gui.py +++ b/winehelper_gui.py @@ -1762,6 +1762,7 @@ class WineHelperGUI(QMainWindow): if show_global: self.backup_button.setVisible(False) self.create_log_button.setVisible(False) + self.open_log_dir_button.setVisible(False) self.uninstall_button.setVisible(False) self.current_selected_app = None @@ -1877,6 +1878,12 @@ class WineHelperGUI(QMainWindow): self.backup_button.clicked.connect(self.backup_prefix_for_app) installed_global_layout.addWidget(self.backup_button) + self.open_log_dir_button = QPushButton("Открыть папку с логом/резервной копией префикса") + self.open_log_dir_button.setIcon(QIcon.fromTheme("folder-open")) + self.open_log_dir_button.clicked.connect(self.open_log_directory) + self.open_log_dir_button.setVisible(False) # Скрыта по умолчанию + installed_global_layout.addWidget(self.open_log_dir_button) + self.uninstall_button = QPushButton("Удалить префикс") self.uninstall_button.setIcon(QIcon.fromTheme("user-trash")) self.uninstall_button.clicked.connect(self.uninstall_app) @@ -2172,6 +2179,13 @@ class WineHelperGUI(QMainWindow): self.created_prefix_selector.currentIndexChanged.connect(self.on_created_prefix_selected) selector_layout.addWidget(self.created_prefix_selector, 1) + self.open_prefix_folder_button = QPushButton() + self.open_prefix_folder_button.setIcon(QIcon.fromTheme("folder-open")) + self.open_prefix_folder_button.setToolTip("Открыть папку префикса в файловом менеджере") + self.open_prefix_folder_button.setEnabled(False) + self.open_prefix_folder_button.clicked.connect(self.open_selected_prefix_folder) + selector_layout.addWidget(self.open_prefix_folder_button) + self.create_base_pfx_button = QPushButton() self.create_base_pfx_button.setIcon(QIcon.fromTheme("document-export")) self.create_base_pfx_button.setToolTip("Создать шаблон из выбранного префикса (для опытных пользователей)") @@ -2316,6 +2330,24 @@ class WineHelperGUI(QMainWindow): management_layout.setColumnStretch(2, 2) container_layout.addWidget(self.prefix_management_groupbox) + + # --- Кнопка полного удаления --- + # Добавляем разделитель и кнопку в основной контейнер управления + container_layout.addSpacing(15) + self.remove_all_button = QPushButton("Удалить все данные WineHelper") + self.remove_all_button.setStyleSheet(""" + QPushButton:!disabled { + background-color: #d32f2f; + color: white; + padding: 5px; + } + """) + self.remove_all_button.setMinimumHeight(32) + self.remove_all_button.setFont(QFont('Arial', 10, QFont.Bold)) + self.remove_all_button.setToolTip("ВНИМАНИЕ: Удаляет ВСЕ данные WineHelper, включая все префиксы, настройки и ярлыки.") + self.remove_all_button.clicked.connect(self.remove_all_data) + container_layout.addWidget(self.remove_all_button) + layout.addWidget(self.management_container_groupbox) layout.addStretch() self.add_tab(self.prefix_tab, "Менеджер префиксов") @@ -2357,6 +2389,7 @@ class WineHelperGUI(QMainWindow): prefix_names = [] self.created_prefix_selector.blockSignals(True) + self.remove_all_button.setEnabled(bool(prefix_names)) self.created_prefix_selector.clear() if prefix_names: self.created_prefix_selector.addItems(prefix_names) @@ -2372,7 +2405,9 @@ class WineHelperGUI(QMainWindow): self.current_managed_prefix_name = None self._setup_prefix_management_panel(None) self.delete_prefix_button.setEnabled(False) + self.remove_all_button.setEnabled(False) self.create_base_pfx_button.setEnabled(False) + self.open_prefix_folder_button.setEnabled(False) else: # Прокручиваем к выбранному элементу, чтобы он был виден в списке self.created_prefix_selector.view().scrollTo( @@ -2382,7 +2417,9 @@ class WineHelperGUI(QMainWindow): self.current_managed_prefix_name = prefix_name self._setup_prefix_management_panel(prefix_name) self.delete_prefix_button.setEnabled(True) + self.remove_all_button.setEnabled(True) self.create_base_pfx_button.setEnabled(True) + self.open_prefix_folder_button.setEnabled(True) def delete_selected_prefix(self): """Удаляет префикс, выбранный в выпадающем списке на вкладке 'Менеджер префиксов'.""" @@ -2491,6 +2528,21 @@ class WineHelperGUI(QMainWindow): self._run_simple_command("create-base-pfx", [prefix_name]) self.command_dialog.exec_() + def open_selected_prefix_folder(self): + """Открывает папку выбранного префикса в системном файловом менеджере.""" + prefix_name = self.current_managed_prefix_name + if not prefix_name: + return + + prefix_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name) + if os.path.isdir(prefix_path): + try: + subprocess.Popen(['xdg-open', prefix_path]) + except Exception as e: + QMessageBox.warning(self, "Ошибка", f"Не удалось открыть директорию:\n{prefix_path}\n\nОшибка: {e}") + else: + QMessageBox.warning(self, "Ошибка", f"Директория префикса не найдена:\n{prefix_path}") + def _setup_prefix_management_panel(self, prefix_name): """Настраивает панель управления префиксом на основе текущего состояния.""" is_prefix_selected = bool(prefix_name) @@ -3378,6 +3430,7 @@ class WineHelperGUI(QMainWindow): self.installed_global_action_widget.setVisible(True) self.backup_button.setVisible(True) self.create_log_button.setVisible(True) + self.update_open_log_dir_button_visibility() self.uninstall_button.setVisible(True) self.manual_install_path_widget.setVisible(False) @@ -3386,6 +3439,27 @@ class WineHelperGUI(QMainWindow): self.current_selected_app = None self.info_panel.setVisible(False) + def update_open_log_dir_button_visibility(self): + """Проверяет наличие лог-файла или бэкапов и обновляет видимость кнопки.""" + log_dir_path = os.path.join(os.path.expanduser("~"), "winehelper_backup_log") + is_visible = False + if os.path.isdir(log_dir_path): + # Кнопка должна быть видна, если директория не пуста. + if os.listdir(log_dir_path): + is_visible = True + self.open_log_dir_button.setVisible(is_visible) + + def open_log_directory(self): + """Открывает директорию с лог-файлами.""" + log_dir_path = os.path.join(os.path.expanduser("~"), "winehelper_backup_log") + if os.path.isdir(log_dir_path): + try: + subprocess.Popen(['xdg-open', log_dir_path]) + except Exception as e: + QMessageBox.warning(self, "Ошибка", f"Не удалось открыть директорию:\n{log_dir_path}\n\nОшибка: {e}") + else: + QMessageBox.information(self, "Информация", f"Директория с логами не найдена:\n{log_dir_path}") + def _get_prefix_name_for_selected_app(self): """Извлекает имя префикса для выбранного приложения.""" if not self.current_selected_app or 'desktop_path' not in self.current_selected_app: @@ -3426,8 +3500,8 @@ class WineHelperGUI(QMainWindow): msg_box = QMessageBox(self) msg_box.setWindowTitle("Создание резервной копии") msg_box.setText( - f"Будет создана резервная копия префикса '{prefix_name}'.\n" - f"Файл будет сохранен на вашем Рабочем столе в формате .whpack.\n\nПродолжить?" + f"Будет создана резервная копия префикса '{prefix_name}'.\n\n" + f"Файл будет сохранен в домашней директории в папке winehelper_backup_log/ в формате .whpack.\n\nПродолжить?" ) msg_box.addButton(yes_button, QMessageBox.YesRole) msg_box.addButton(no_button, QMessageBox.NoRole) @@ -3460,6 +3534,7 @@ class WineHelperGUI(QMainWindow): self.command_process.setProcessChannelMode(QProcess.MergedChannels) self.command_process.readyReadStandardOutput.connect(self._handle_command_output) self.command_process.finished.connect(self._handle_command_finished) + self.command_process.finished.connect(self.update_open_log_dir_button_visibility) winehelper_path = self.winehelper_path args = ["backup-prefix", prefix_name] @@ -3525,9 +3600,9 @@ class WineHelperGUI(QMainWindow): msg_box = QMessageBox(self) msg_box.setWindowTitle("Создание лога") msg_box.setText( - "Приложение будет запущено в режиме отладки.\n" - "После закрытия приложения лог будет сохранен в вашем домашнем каталоге " - "под именем 'winehelper.log'." + "Приложение будет запущено в режиме отладки.\n\n" + "После закрытия приложения лог будет сохранен в папке 'winehelper_backup_log' " + "в вашем домашнем каталоге под именем 'winehelper.log'." ) msg_box.addButton(yes_button, QMessageBox.YesRole) msg_box.addButton(no_button, QMessageBox.NoRole) @@ -3793,6 +3868,7 @@ class WineHelperGUI(QMainWindow): # и избегания проблем с замыканием в lambda. process.finished.connect(partial(self._on_app_process_finished, desktop_path)) + process.finished.connect(self.update_open_log_dir_button_visibility) try: process.start(program, arguments) @@ -3811,6 +3887,55 @@ class WineHelperGUI(QMainWindow): QMessageBox.critical(self, "Ошибка", f"Не удалось обработать команду запуска:\n{command_str}\n\nОшибка: {str(e)}") + def remove_all_data(self): + """Запускает процесс полного удаления всех данных WineHelper.""" + # Первое подтверждение + msg_box1 = QMessageBox(self) + msg_box1.setIcon(QMessageBox.Critical) + msg_box1.setWindowTitle('Подтверждение полного удаления') + msg_box1.setText( + "

ВНИМАНИЕ!

" + "

Это действие полностью и безвозвратно удалит ВСЕ данные, связанные с WineHelper, включая:

" + "" + "

Продолжить?

" + ) + msg_box1.setTextFormat(Qt.RichText) + yes_button1 = msg_box1.addButton("Да, я понимаю", QMessageBox.YesRole) + no_button1 = msg_box1.addButton("Отмена", QMessageBox.NoRole) + msg_box1.setDefaultButton(no_button1) + msg_box1.exec_() + + if msg_box1.clickedButton() != yes_button1: + return + + # Второе, финальное подтверждение + msg_box2 = QMessageBox(self) + msg_box2.setIcon(QMessageBox.Critical) + msg_box2.setWindowTitle('Последнее предупреждение') + msg_box2.setText("

Вы уверены, что хотите удалить ВСЁ?

Это действие необратимо.

") + msg_box2.setTextFormat(Qt.RichText) + yes_button2 = msg_box2.addButton("Да, удалить всё", QMessageBox.DestructiveRole) + no_button2 = msg_box2.addButton("Нет, я передумал", QMessageBox.RejectRole) + msg_box2.setDefaultButton(no_button2) + msg_box2.exec_() + + if msg_box2.clickedButton() != yes_button2: + return + + # Запускаем команду и выходим из приложения + try: + # Запускаем команду в фоне и не ждем ее завершения + subprocess.Popen([self.winehelper_path, "remove-all", "--force"]) + # Сообщаем пользователю и закрываем GUI + QMessageBox.information(self, "Удаление", "Запущена процедура удаления WineHelper. Приложение будет закрыто.") + self.quit_application() + except Exception as e: + QMessageBox.critical(self, "Ошибка", f"Не удалось запустить команду удаления: {e}") + def quit_application(self): """Инициирует процесс выхода из приложения.""" self.is_quitting = True