@@ -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 (
" <h2>ВНИМАНИЕ!</h2> "
" <p>Это действие полностью и безвозвратно удалит <b>В С Е </b> данные, связанные с WineHelper, включая:</p> "
" <ul> "
" <li>В с е созданные префиксы и установленные в них программы.</li> "
" <li>В с е ярлыки в меню и на рабочем столе.</li> "
" <li>В с е настройки, кэш и резервные копии.</li> "
" </ul> "
" <p>Продолжить?</p> "
)
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 ( " <h3>Вы уверены, что хотите удалить ВСЁ?</h3><p>Это действие необратимо.</p> " )
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