Merge branch 'minergenon-devel'
This commit is contained in:
		| @@ -5,7 +5,7 @@ export WH_WINDOWS_VER="10" | |||||||
| export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | ||||||
| export BASE_PFX="tflex17_pfx_x64_v02" | export BASE_PFX="tflex17_pfx_x64_v02" | ||||||
| export WINEARCH="win64" | export WINEARCH="win64" | ||||||
| export WINEPREFIX="tflex17" | export WINEPREFIX="tflex" | ||||||
| export PROG_VERSION="" | export PROG_VERSION="" | ||||||
| export WH_XDG_OPEN="log" | export WH_XDG_OPEN="log" | ||||||
| export INSTALL_DLL="corefonts d3dcompiler_47 dotnet48 vcrun2022 ucrtbase2019 msxml6 fontsmooth=rgb baekmuk droid eufonts ipamona liberation lucida opensymbol sourcehansans tahoma takao uff unifont vlgothic wenquanyi wenquanyizenhei" | export INSTALL_DLL="corefonts d3dcompiler_47 dotnet48 vcrun2022 ucrtbase2019 msxml6 fontsmooth=rgb baekmuk droid eufonts ipamona liberation lucida opensymbol sourcehansans tahoma takao uff unifont vlgothic wenquanyi wenquanyizenhei" | ||||||
|   | |||||||
							
								
								
									
										152
									
								
								winehelper
									
									
									
									
									
								
							
							
						
						
									
										152
									
								
								winehelper
									
									
									
									
									
								
							| @@ -190,7 +190,7 @@ su_run () { | |||||||
|             ((i++)) |             ((i++)) | ||||||
|         done |         done | ||||||
|     else |     else | ||||||
|         pkexec "$@" && return 0 |         pkexec bash -c "$@" && return 0 | ||||||
|     fi |     fi | ||||||
|     fatal "Не удалось установить необходимые компоненты!" |     fatal "Не удалось установить необходимые компоненты!" | ||||||
| } | } | ||||||
| @@ -509,63 +509,29 @@ var_ld_library_path_update () { | |||||||
|     return 0 |     return 0 | ||||||
| } | } | ||||||
|  |  | ||||||
| extract_icon() { |  | ||||||
|     check_prefix_var |  | ||||||
|     local exe_file="$1" |  | ||||||
|     local ico_name="$(basename "$exe_file" .exe).ico" |  | ||||||
|     local png_name="$(basename "$exe_file" .exe).png" |  | ||||||
|     local tmp_ico_dir="$WH_TMP_DIR/icons" |  | ||||||
|     local user_icons="$WINEPREFIX/icons" |  | ||||||
|  |  | ||||||
|     create_new_dir "$tmp_ico_dir" |  | ||||||
|  |  | ||||||
|     if ! wrestool -x -t 14 "$exe_file" -o "$tmp_ico_dir/$ico_name" ; then |  | ||||||
|         print_warning "Не удалось извлечь иконку из $exe_file" |  | ||||||
|         try_remove_file "$tmp_ico_dir" |  | ||||||
|         return 1 |  | ||||||
|     fi |  | ||||||
|  |  | ||||||
|     if ! icotool -x -i 1 "$tmp_ico_dir/$ico_name" -o "$tmp_ico_dir/$png_name" ; then |  | ||||||
|         print_warning "Не удалось извлечь иконку из $ico_name" |  | ||||||
|         try_remove_file "$tmp_ico_dir" |  | ||||||
|         return 1 |  | ||||||
|     fi |  | ||||||
|  |  | ||||||
|     create_new_dir "$user_icons" |  | ||||||
|  |  | ||||||
|     if ! try_copy_file "$tmp_ico_dir/$png_name" "$user_icons" ; then |  | ||||||
|         print_warning "Не удалось копировать иконку в префикс" |  | ||||||
|         try_remove_file "$user_icons" |  | ||||||
|         return 1 |  | ||||||
|     fi |  | ||||||
|  |  | ||||||
|     try_remove_dir "$tmp_ico_dir" |  | ||||||
|     print_ok "Иконка сохранена: $user_icons/$png_name" |  | ||||||
|     return 0 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| create_desktop () { | create_desktop () { | ||||||
|     local name_desktop exe_file desktop_filename icon_file desktop_path |     local name_desktop exe_file desktop_filename icon_file desktop_path icon_arg desktop_filename_arg | ||||||
|     name_desktop="$1" |     name_desktop="$1" | ||||||
|     exe_file="$2" |     exe_file="$2" | ||||||
|     if [[ -n $4 ]] && [[ $4 != "nocopy" ]]; |     icon_arg="$3" | ||||||
|     then desktop_filename="$4" |     desktop_filename_arg="$4" | ||||||
|     else desktop_filename="$(basename "$exe_file" .exe | sed "s| |_|")" |  | ||||||
|     fi |     # Определяем имя desktop-файла | ||||||
|     if [[ "$RESTORE_FROM_BACKUP" == "1" ]] && [[ -f "$3" ]] |     if [[ -n "$desktop_filename_arg" ]] && [[ "$desktop_filename_arg" != "nocopy" ]]; then | ||||||
|     then icon_file="$3" |         desktop_filename="$desktop_filename_arg" | ||||||
|     elif [[ -f "$WH_IMAGE_PATH/$3.png" ]] |     else | ||||||
|     then icon_file="$WH_IMAGE_PATH/$3.png" |         desktop_filename="$(basename "$exe_file" .exe | sed "s| |_|g")" | ||||||
|     else icon_file="wine" |  | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|  |     # Проверяем обязательные аргументы и наличие exe-файла | ||||||
|     if [[ -z "$name_desktop" ]] || [[ -z "$exe_file" ]] ; then |     if [[ -z "$name_desktop" ]] || [[ -z "$exe_file" ]] ; then | ||||||
|         fatal "Used: $SCRIPT_NAME --desktop \"desktop_name\" \"path_to_exe\" \"name_png_from_image\"" |         fatal "Использование: $0 create-desktop \"Имя ярлыка\" \"/путь/к/файлу.exe\" [иконка|auto] [имя_desktop_файла]" | ||||||
|     elif [[ ! -f "$exe_file" ]] ; then |     elif [[ ! -f "$exe_file" ]] ; then | ||||||
|         print_warning "Для создания ярлыка не найден исполняемый файл: $exe_file" |         print_warning "Для создания ярлыка не найден исполняемый файл: $exe_file" | ||||||
|  |  | ||||||
|         BASENAME_EXE="$(basename "$exe_file")" |         local BASENAME_EXE="$(basename "$exe_file")" | ||||||
|         print_info "Запускаем поиск $BASENAME_EXE" |         print_info "Запускаем поиск $BASENAME_EXE" | ||||||
|  |         local FIND_PATH | ||||||
|         if [[ -z "$DRIVE_C" ]] || [[ ! -d "$DRIVE_C" ]] |         if [[ -z "$DRIVE_C" ]] || [[ ! -d "$DRIVE_C" ]] | ||||||
|         then FIND_PATH="$WH_PREFIXES_DIR" |         then FIND_PATH="$WH_PREFIXES_DIR" | ||||||
|         else FIND_PATH="$DRIVE_C" |         else FIND_PATH="$DRIVE_C" | ||||||
| @@ -575,11 +541,55 @@ create_desktop () { | |||||||
|                     -iname "$BASENAME_EXE")" |                     -iname "$BASENAME_EXE")" | ||||||
|         if [[ -z "$exe_file" ]] || [[ ! -f "$exe_file" ]] |         if [[ -z "$exe_file" ]] || [[ ! -f "$exe_file" ]] | ||||||
|         then fatal "Для создания ярлыка не найден исполняемый файл: $BASENAME_EXE" |         then fatal "Для создания ярлыка не найден исполняемый файл: $BASENAME_EXE" | ||||||
|         else print_ok "Исполняемый файл $BASENAME_EXE найден по пути $(dirname "$exe_file")/" |         else print_ok "Исполняемый файл $BASENAME_EXE найден по пути: $(dirname "$exe_file")/" | ||||||
|         fi |         fi | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|     # создаем .desktop файл |     # --- Логика обработки иконки --- | ||||||
|  |     local user_icons_dir="$WINEPREFIX/icons" | ||||||
|  |     create_new_dir "$user_icons_dir" | ||||||
|  |  | ||||||
|  |     # Случай 1: Восстановление из бэкапа (передан явный путь) | ||||||
|  |     if [[ "$RESTORE_FROM_BACKUP" == "1" ]] && [[ -f "$icon_arg" ]]; then | ||||||
|  |         icon_file="$icon_arg" | ||||||
|  |     # Случай 2: 'auto' или пустой аргумент - пытаемся извлечь из EXE | ||||||
|  |     elif [[ -z "$icon_arg" ]] || [[ "$icon_arg" == "auto" ]]; then | ||||||
|  |         print_info "Попытка извлечь иконку из $exe_file..." | ||||||
|  |         local png_name="$(basename "$exe_file" .exe).png" | ||||||
|  |         local extracted_icon_path="$user_icons_dir/$png_name" | ||||||
|  |  | ||||||
|  |         # Проверяем, существует ли иконка, чтобы избежать повторного извлечения | ||||||
|  |         if [[ -f "$extracted_icon_path" ]]; then | ||||||
|  |             print_info "Иконка уже существует: $extracted_icon_path" | ||||||
|  |             icon_file="$extracted_icon_path" | ||||||
|  |         else | ||||||
|  |             local tmp_ico_dir="$WH_TMP_DIR/icons_$$" # Используем PID для временного каталога | ||||||
|  |             create_new_dir "$tmp_ico_dir" | ||||||
|  |             local ico_name="$(basename "$exe_file" .exe).ico" | ||||||
|  |  | ||||||
|  |             if wrestool -x -t 14 "$exe_file" -o "$tmp_ico_dir/$ico_name" &>/dev/null && \ | ||||||
|  |                icotool -x -i 1 "$tmp_ico_dir/$ico_name" -o "$tmp_ico_dir/$png_name" &>/dev/null && \ | ||||||
|  |                try_copy_file "$tmp_ico_dir/$png_name" "$user_icons_dir/"; then | ||||||
|  |  | ||||||
|  |                 icon_file="$extracted_icon_path" | ||||||
|  |                 print_ok "Иконка успешно извлечена и сохранена: $icon_file" | ||||||
|  |             else | ||||||
|  |                 print_warning "Не удалось извлечь иконку из $exe_file. Используется иконка по умолчанию." | ||||||
|  |                 icon_file="wine" # Запасной вариант | ||||||
|  |             fi | ||||||
|  |             try_remove_dir "$tmp_ico_dir" | ||||||
|  |         fi | ||||||
|  |     # Случай 3: Передано конкретное имя иконки | ||||||
|  |     elif [[ -f "$WH_IMAGE_PATH/$icon_arg.png" ]]; then | ||||||
|  |         icon_file="$WH_IMAGE_PATH/$icon_arg.png" | ||||||
|  |     # Случай 4: Запасной вариант по умолчанию | ||||||
|  |     else | ||||||
|  |         print_info "Иконка '$icon_arg' не найдена. Используется иконка по умолчанию." | ||||||
|  |         icon_file="wine" | ||||||
|  |     fi | ||||||
|  |     # --- Конец логики обработки иконки --- | ||||||
|  |  | ||||||
|  |     # Создаем .desktop файл | ||||||
|     create_new_dir "$WH_MENU_DIR" |     create_new_dir "$WH_MENU_DIR" | ||||||
|     { |     { | ||||||
|         echo "[Desktop Entry]" |         echo "[Desktop Entry]" | ||||||
| @@ -596,19 +606,29 @@ create_desktop () { | |||||||
|     cp -f "$USER_WORK_PATH/$desktop_filename.desktop" "$WH_MENU_DIR/" |     cp -f "$USER_WORK_PATH/$desktop_filename.desktop" "$WH_MENU_DIR/" | ||||||
|  |  | ||||||
|     if [[ "$RESTORE_FROM_BACKUP" == "1" ]] ; then |     if [[ "$RESTORE_FROM_BACKUP" == "1" ]] ; then | ||||||
|         print_info "Пропускаем обновление desktop.list (режим восстановления из бэкапа)" |         print_info "Пропускаем обновление desktop.list (режим восстановления)" | ||||||
|     else |     else | ||||||
|         # добавляем информацию о приложении в "$WINEPREFIX/desktop.list" |         # Добавляем информацию о приложении в "$WINEPREFIX/desktop.list" | ||||||
|         if [[ -f "$WINEPREFIX/desktop.list" ]] \ |         if [[ -f "$WINEPREFIX/desktop.list" ]] \ | ||||||
|         && grep -qe "^${name_desktop}=" "$WINEPREFIX/desktop.list" |         && grep -qe "^${name_desktop}=" "$WINEPREFIX/desktop.list" | ||||||
|         then sed -i "/^$name_desktop=/d" "$WINEPREFIX/desktop.list" |         then sed -i "/^$name_desktop=/d" "$WINEPREFIX/desktop.list" | ||||||
|         fi |         fi | ||||||
|         create_new_dir "$WINEPREFIX/icons" |  | ||||||
|         try_copy_file "$icon_file" "$WINEPREFIX/icons/" |         # Копируем финальную иконку в директорию иконок префикса, если ее там нет | ||||||
|         echo "$name_desktop=${exe_file//$WINEPREFIX/}=$(basename "$icon_file")" >> "$WINEPREFIX/desktop.list" |         local final_icon_name | ||||||
|  |         if [[ -f "$icon_file" ]]; then | ||||||
|  |             final_icon_name=$(basename "$icon_file") | ||||||
|  |             if [[ ! -f "$user_icons_dir/$final_icon_name" ]]; then | ||||||
|  |                 try_copy_file "$icon_file" "$user_icons_dir/" | ||||||
|  |             fi | ||||||
|  |         else | ||||||
|  |             final_icon_name="$icon_file" # например, "wine" | ||||||
|  |         fi | ||||||
|  |  | ||||||
|  |         echo "$name_desktop=${exe_file//$WINEPREFIX/}=${final_icon_name}" >> "$WINEPREFIX/desktop.list" | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|     # создаем файл категории для меню |     # Создаем файл категории для меню | ||||||
|     create_new_dir "$HOME/.local/share/desktop-directories" |     create_new_dir "$HOME/.local/share/desktop-directories" | ||||||
|     if [[ ! -f "$WH_MENU_CATEGORY" ]] ; then |     if [[ ! -f "$WH_MENU_CATEGORY" ]] ; then | ||||||
|     cat > "$WH_MENU_CATEGORY" <<EOF |     cat > "$WH_MENU_CATEGORY" <<EOF | ||||||
| @@ -619,7 +639,7 @@ Icon=wine | |||||||
| EOF | EOF | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|     # Создаем файл меню для всех приложений |     # Создаем файл меню для всех приложений WineHelper | ||||||
|     create_new_dir "$HOME/.config/menus/applications-merged" |     create_new_dir "$HOME/.config/menus/applications-merged" | ||||||
|     if [[ ! -f "$WH_MENU_CONFIG" ]] ; then |     if [[ ! -f "$WH_MENU_CONFIG" ]] ; then | ||||||
|     cat > "$WH_MENU_CONFIG" <<EOF |     cat > "$WH_MENU_CONFIG" <<EOF | ||||||
| @@ -638,15 +658,15 @@ EOF | |||||||
| EOF | EOF | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|     # Обновляем кэш desktop файлов |     # Обновляем кэш desktop-файлов | ||||||
|     update-desktop-database "$HOME/.local/share/applications" |     update-desktop-database "$HOME/.local/share/applications" | ||||||
|  |  | ||||||
|     if [[ $4 != "nocopy" ]] ; then |     if [[ "$desktop_filename_arg" != "nocopy" ]] ; then | ||||||
|         desktop_path="$(xdg-user-dir DESKTOP)" |         desktop_path="$(xdg-user-dir DESKTOP)" | ||||||
|         print_info "В меню и на рабочем столе создан $desktop_filename.desktop" |         print_info "В меню и на рабочем столе создан ярлык: $desktop_filename.desktop" | ||||||
|         cp -f "$USER_WORK_PATH/$desktop_filename.desktop" "$desktop_path" |         cp -f "$USER_WORK_PATH/$desktop_filename.desktop" "$desktop_path" | ||||||
|     else |     else | ||||||
|         print_info "В меню создан $desktop_filename.desktop" |         print_info "В меню создан ярлык: $desktop_filename.desktop" | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|     if [[ -n "$INSTALL_SCRIPT_NAME" ]] \ |     if [[ -n "$INSTALL_SCRIPT_NAME" ]] \ | ||||||
| @@ -2044,6 +2064,16 @@ case "$arg1" in | |||||||
|     *) |     *) | ||||||
|         if [[ -f "$arg1" ]] ; then |         if [[ -f "$arg1" ]] ; then | ||||||
|             WIN_FILE_EXEC="$(readlink -f "$arg1")" |             WIN_FILE_EXEC="$(readlink -f "$arg1")" | ||||||
|  |  | ||||||
|  |             # Автоматическое определение префикса, если он не задан | ||||||
|  |             if [[ -z "$WINEPREFIX" ]] && [[ "$WIN_FILE_EXEC" == "$WH_PREFIXES_DIR"* ]]; then | ||||||
|  |                 extracted_prefix="$(echo "$WIN_FILE_EXEC" | grep -o ".*/prefixes/[^/]*")" | ||||||
|  |                 if [[ -d "$extracted_prefix" ]]; then | ||||||
|  |                     export WINEPREFIX="$extracted_prefix" | ||||||
|  |                     print_info "Префикс автоматически определен: $(basename "$WINEPREFIX")" | ||||||
|  |                 fi | ||||||
|  |             fi | ||||||
|  |  | ||||||
|             WIN_FILE_NAME="$(basename "$arg1")" |             WIN_FILE_NAME="$(basename "$arg1")" | ||||||
|             case "${WIN_FILE_NAME,,}" in |             case "${WIN_FILE_NAME,,}" in | ||||||
|                 *.exe) prepair_wine ; wine_run $WINE_WIN_START "$WIN_FILE_EXEC" "$@" ;; |                 *.exe) prepair_wine ; wine_run $WINE_WIN_START "$WIN_FILE_EXEC" "$@" ;; | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ import hashlib | |||||||
| from functools import partial | from functools import partial | ||||||
| from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,QPushButton, QLabel, QTabWidget, QTabBar, | from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,QPushButton, QLabel, QTabWidget, QTabBar, | ||||||
|                              QTextEdit, QFileDialog, QMessageBox, QLineEdit, QCheckBox, QStackedWidget, QScrollArea, QFormLayout, QGroupBox, QRadioButton, QComboBox, |                              QTextEdit, QFileDialog, QMessageBox, QLineEdit, QCheckBox, QStackedWidget, QScrollArea, QFormLayout, QGroupBox, QRadioButton, QComboBox, | ||||||
|                              QListWidget, QListWidgetItem, QGridLayout, QFrame, QDialog, QTextBrowser) |                              QListWidget, QListWidgetItem, QGridLayout, QFrame, QDialog, QTextBrowser, QInputDialog) | ||||||
| from PyQt5.QtCore import Qt, QProcess, QSize, QTimer, QProcessEnvironment, QPropertyAnimation, QEasingCurve | from PyQt5.QtCore import Qt, QProcess, QSize, QTimer, QProcessEnvironment, QPropertyAnimation, QEasingCurve | ||||||
| from PyQt5.QtGui import QIcon, QFont, QTextCursor, QPixmap, QPainter, QDesktopServices | from PyQt5.QtGui import QIcon, QFont, QTextCursor, QPixmap, QPainter, QDesktopServices | ||||||
| from PyQt5.QtNetwork import QLocalServer, QLocalSocket | from PyQt5.QtNetwork import QLocalServer, QLocalSocket | ||||||
| @@ -965,7 +965,8 @@ class ScriptParser: | |||||||
|                             if part == 'create_desktop': |                             if part == 'create_desktop': | ||||||
|                                 if len(parts) > i + 3: |                                 if len(parts) > i + 3: | ||||||
|                                     icon_name = parts[i + 3] |                                     icon_name = parts[i + 3] | ||||||
|                                     if icon_name: |                                     # Игнорируем служебные слова, которые не являются иконками | ||||||
|  |                                     if icon_name and icon_name.lower() not in ('auto', 'nocopy'): | ||||||
|                                         icon_names.append(icon_name) |                                         icon_names.append(icon_name) | ||||||
|                     except (ValueError, IndexError): |                     except (ValueError, IndexError): | ||||||
|                         continue |                         continue | ||||||
| @@ -1975,7 +1976,7 @@ class WineHelperGUI(QMainWindow): | |||||||
|  |  | ||||||
|         install_path_layout = QHBoxLayout() |         install_path_layout = QHBoxLayout() | ||||||
|         self.prefix_install_path_edit = QLineEdit() |         self.prefix_install_path_edit = QLineEdit() | ||||||
|         self.prefix_install_path_edit.setPlaceholderText("Путь к .exe или .msi файлу...") |         self.prefix_install_path_edit.setPlaceholderText("Укажите путь к установочному файлу .exe или .msi...") | ||||||
|         install_path_layout.addWidget(self.prefix_install_path_edit) |         install_path_layout.addWidget(self.prefix_install_path_edit) | ||||||
|  |  | ||||||
|         self.prefix_browse_button = QPushButton("Обзор...") |         self.prefix_browse_button = QPushButton("Обзор...") | ||||||
| @@ -1983,10 +1984,21 @@ class WineHelperGUI(QMainWindow): | |||||||
|         install_path_layout.addWidget(self.prefix_browse_button) |         install_path_layout.addWidget(self.prefix_browse_button) | ||||||
|         install_layout.addLayout(install_path_layout) |         install_layout.addLayout(install_path_layout) | ||||||
|  |  | ||||||
|  |         # Layout для кнопок установки и создания ярлыка | ||||||
|  |         action_buttons_layout = QHBoxLayout() | ||||||
|  |  | ||||||
|         self.prefix_install_button = QPushButton("Установить приложение в префикс") |         self.prefix_install_button = QPushButton("Установить приложение в префикс") | ||||||
|         self.prefix_install_button.setEnabled(False) |         self.prefix_install_button.setEnabled(False) | ||||||
|         self.prefix_install_button.clicked.connect(self.run_prefix_installer) |         self.prefix_install_button.clicked.connect(self.run_prefix_installer) | ||||||
|         install_layout.addWidget(self.prefix_install_button) |         action_buttons_layout.addWidget(self.prefix_install_button) | ||||||
|  |  | ||||||
|  |         self.create_launcher_button = QPushButton("Создать ярлык для приложения в префиксе") | ||||||
|  |         self.create_launcher_button.setToolTip( | ||||||
|  |             "Создает ярлык в меню и на вкладке 'Установленные' для .exe файла внутри префикса.") | ||||||
|  |         self.create_launcher_button.clicked.connect(self.create_launcher_for_prefix) | ||||||
|  |         self.create_launcher_button.setEnabled(False)  # Изначально неактивна | ||||||
|  |         action_buttons_layout.addWidget(self.create_launcher_button) | ||||||
|  |         install_layout.addLayout(action_buttons_layout) | ||||||
|  |  | ||||||
|         management_layout.addWidget(install_group, 4, 0, 1, 3) |         management_layout.addWidget(install_group, 4, 0, 1, 3) | ||||||
|  |  | ||||||
| @@ -2001,6 +2013,19 @@ class WineHelperGUI(QMainWindow): | |||||||
|         self.wine_version_edit.textChanged.connect(self.update_create_prefix_button_state) |         self.wine_version_edit.textChanged.connect(self.update_create_prefix_button_state) | ||||||
|         self.prefix_install_path_edit.textChanged.connect(self.update_prefix_install_button_state) |         self.prefix_install_path_edit.textChanged.connect(self.update_prefix_install_button_state) | ||||||
|  |  | ||||||
|  |     def _remove_prefix_from_gui_state(self, prefix_name): | ||||||
|  |         """Удаляет префикс из внутреннего состояния и пользовательского интерфейса вкладки 'Создать префикс'.""" | ||||||
|  |         if prefix_name in self.created_prefixes_info: | ||||||
|  |             del self.created_prefixes_info[prefix_name] | ||||||
|  |  | ||||||
|  |         index_to_remove = self.created_prefix_selector.findText(prefix_name) | ||||||
|  |         if index_to_remove != -1: | ||||||
|  |             self.created_prefix_selector.removeItem(index_to_remove) | ||||||
|  |  | ||||||
|  |         # Сохраняем состояние после удаления. on_created_prefix_selected также вызовет сохранение, | ||||||
|  |         # но этот вызов гарантирует сохранение, даже если сигналы были заблокированы. | ||||||
|  |         self._save_state() | ||||||
|  |  | ||||||
|     def _load_state(self): |     def _load_state(self): | ||||||
|         """Загружает последнее состояние GUI из файла.""" |         """Загружает последнее состояние GUI из файла.""" | ||||||
|         if not os.path.exists(self.state_file): |         if not os.path.exists(self.state_file): | ||||||
| @@ -2075,31 +2100,59 @@ class WineHelperGUI(QMainWindow): | |||||||
|         msg_box.setIcon(QMessageBox.Question) |         msg_box.setIcon(QMessageBox.Question) | ||||||
|         msg_box.setWindowTitle('Подтверждение удаления') |         msg_box.setWindowTitle('Подтверждение удаления') | ||||||
|         msg_box.setText(f'Вы уверены, что хотите удалить префикс "{prefix_name}"?\n\n' |         msg_box.setText(f'Вы уверены, что хотите удалить префикс "{prefix_name}"?\n\n' | ||||||
|                         'Это действие необратимо и удалит все данные внутри префикса.') |                         'Это действие необратимо и удалит все данные внутри префикса, а также все связанные с ним ярлыки.') | ||||||
|  |  | ||||||
|         yes_button = msg_box.addButton("Да", QMessageBox.YesRole) |         yes_button = msg_box.addButton("Да, удалить", QMessageBox.YesRole) | ||||||
|         no_button = msg_box.addButton("Нет", QMessageBox.NoRole) |         no_button = msg_box.addButton("Нет", QMessageBox.NoRole) | ||||||
|         msg_box.setDefaultButton(no_button) |         msg_box.setDefaultButton(no_button) | ||||||
|  |  | ||||||
|         msg_box.exec_() |         msg_box.exec_() | ||||||
|  |  | ||||||
|         # Если пользователь нажал не "Да", выходим |  | ||||||
|         if msg_box.clickedButton() != yes_button: |         if msg_box.clickedButton() != yes_button: | ||||||
|             return |             return | ||||||
|  |  | ||||||
|         prefix_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name) |         # Используем модальный диалог для отображения процесса удаления | ||||||
|  |         self.command_dialog = QDialog(self) | ||||||
|  |         self.command_dialog.setWindowTitle(f"Удаление префикса: {prefix_name}") | ||||||
|  |         self.command_dialog.setMinimumSize(750, 400) | ||||||
|  |         self.command_dialog.setModal(True) | ||||||
|  |         self.command_dialog.setWindowFlags(self.command_dialog.windowFlags() & ~Qt.WindowCloseButtonHint) | ||||||
|  |  | ||||||
|         try: |         layout = QVBoxLayout() | ||||||
|             if os.path.isdir(prefix_path): |         self.command_log_output = QTextEdit() | ||||||
|                 shutil.rmtree(prefix_path) |         self.command_log_output.setReadOnly(True) | ||||||
|             if prefix_name in self.created_prefixes_info: |         self.command_log_output.setFont(QFont('DejaVu Sans Mono', 10)) | ||||||
|                 del self.created_prefixes_info[prefix_name] |         layout.addWidget(self.command_log_output) | ||||||
|             index_to_remove = self.created_prefix_selector.findText(prefix_name) |  | ||||||
|             if index_to_remove != -1: |         self.command_close_button = QPushButton("Закрыть") | ||||||
|                 self.created_prefix_selector.removeItem(index_to_remove) |         self.command_close_button.setEnabled(False) | ||||||
|             QMessageBox.information(self, "Успех", f"Префикс '{prefix_name}' был успешно удален.") |         self.command_close_button.clicked.connect(self.command_dialog.close) | ||||||
|         except Exception as e: |         layout.addWidget(self.command_close_button) | ||||||
|             QMessageBox.critical(self, "Ошибка удаления", f"Не удалось удалить префикс '{prefix_name}':\n{e}") |         self.command_dialog.setLayout(layout) | ||||||
|  |  | ||||||
|  |         self.command_process = QProcess(self.command_dialog) | ||||||
|  |         self.command_process.setProcessChannelMode(QProcess.MergedChannels) | ||||||
|  |         self.command_process.readyReadStandardOutput.connect(self._handle_command_output) | ||||||
|  |  | ||||||
|  |         self.command_process.finished.connect( | ||||||
|  |             lambda exit_code, exit_status: self._handle_prefix_deletion_finished(prefix_name, exit_code, exit_status) | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         args = ["remove-prefix", prefix_name, "--force"] | ||||||
|  |         self.command_log_output.append(f"Выполнение: {shlex.quote(self.winehelper_path)} {' '.join(shlex.quote(a) for a in args)}") | ||||||
|  |         self.command_process.start(self.winehelper_path, args) | ||||||
|  |         self.command_dialog.exec_() | ||||||
|  |  | ||||||
|  |     def _handle_prefix_deletion_finished(self, prefix_name, exit_code, exit_status): | ||||||
|  |         """Обрабатывает завершение процесса удаления префикса.""" | ||||||
|  |         self._handle_command_finished(exit_code, exit_status) | ||||||
|  |         if exit_code == 0: | ||||||
|  |             # Успешное удаление, обновляем GUI | ||||||
|  |             self._remove_prefix_from_gui_state(prefix_name) | ||||||
|  |             self.update_installed_apps() | ||||||
|  |             QMessageBox.information(self, "Успех", f"Префикс '{prefix_name}' и все связанные с ним данные были успешно удалены.") | ||||||
|  |         else: | ||||||
|  |             QMessageBox.critical(self, "Ошибка удаления", f"Не удалось удалить префикс '{prefix_name}'.\nПодробности смотрите в логе.") | ||||||
|  |  | ||||||
|     def on_prefix_name_edited(self, text): |     def on_prefix_name_edited(self, text): | ||||||
|         """Сбрасывает состояние управления префиксом, когда пользователь вводит новое имя.""" |         """Сбрасывает состояние управления префиксом, когда пользователь вводит новое имя.""" | ||||||
| @@ -2116,6 +2169,9 @@ class WineHelperGUI(QMainWindow): | |||||||
|             self.prefix_management_groupbox.setEnabled(False) |             self.prefix_management_groupbox.setEnabled(False) | ||||||
|             self.prefix_info_display.clear() |             self.prefix_info_display.clear() | ||||||
|             self.prefix_install_path_edit.clear() |             self.prefix_install_path_edit.clear() | ||||||
|  |         # Кнопка "Создать ярлык" должна быть активна, если выбран действительный префикс | ||||||
|  |         is_prefix_selected = bool(prefix_name and prefix_name in self.created_prefixes_info) | ||||||
|  |         self.create_launcher_button.setEnabled(is_prefix_selected) | ||||||
|         self.update_prefix_install_button_state() |         self.update_prefix_install_button_state() | ||||||
|  |  | ||||||
|     def update_prefix_info_display(self, prefix_name): |     def update_prefix_info_display(self, prefix_name): | ||||||
| @@ -2197,6 +2253,79 @@ class WineHelperGUI(QMainWindow): | |||||||
|         self.command_process.start(wine_executable, args) |         self.command_process.start(wine_executable, args) | ||||||
|         self.command_dialog.exec_() |         self.command_dialog.exec_() | ||||||
|  |  | ||||||
|  |     def create_launcher_for_prefix(self): | ||||||
|  |         """ | ||||||
|  |         Открывает диалог для создания ярлыка для приложения внутри выбранного префикса. | ||||||
|  |         """ | ||||||
|  |         prefix_name = self.current_managed_prefix_name | ||||||
|  |         if not prefix_name: | ||||||
|  |             QMessageBox.warning(self, "Ошибка", "Сначала выберите префикс.") | ||||||
|  |             return | ||||||
|  |  | ||||||
|  |         prefix_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name) | ||||||
|  |         drive_c_path = os.path.join(prefix_path, "drive_c") | ||||||
|  |  | ||||||
|  |         if not os.path.isdir(drive_c_path): | ||||||
|  |             QMessageBox.critical(self, "Ошибка", f"Диск C: для префикса '{prefix_name}' не найден.") | ||||||
|  |             return | ||||||
|  |  | ||||||
|  |         # 1. Открываем диалог выбора файла для .exe | ||||||
|  |         exe_path, _ = QFileDialog.getOpenFileName( | ||||||
|  |             self, | ||||||
|  |             "Выберите исполняемый файл (.exe) для создания ярлыка", | ||||||
|  |             drive_c_path, | ||||||
|  |             "Исполняемые файлы (*.exe)" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         if not exe_path: | ||||||
|  |             return  # Пользователь отменил | ||||||
|  |  | ||||||
|  |         # 2. Запрашиваем имя для ярлыка | ||||||
|  |         app_name, ok = QInputDialog.getText( | ||||||
|  |             self, | ||||||
|  |             "Имя ярлыка", | ||||||
|  |             "Введите имя для нового ярлыка:", | ||||||
|  |             QLineEdit.Normal, | ||||||
|  |             os.path.splitext(os.path.basename(exe_path))[0]  # Предлагаем имя из .exe | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         if not ok or not app_name.strip(): | ||||||
|  |             return  # Пользователь отменил или ввел пустое имя | ||||||
|  |  | ||||||
|  |         # 3. Вызываем winehelper.sh create-desktop | ||||||
|  |         self.command_dialog = QDialog(self) | ||||||
|  |         self.command_dialog.setWindowTitle(f"Создание ярлыка для: {app_name}") | ||||||
|  |         self.command_dialog.setMinimumSize(750, 400) | ||||||
|  |         self.command_dialog.setModal(True) | ||||||
|  |         self.command_dialog.setWindowFlags(self.command_dialog.windowFlags() & ~Qt.WindowCloseButtonHint) | ||||||
|  |  | ||||||
|  |         layout = QVBoxLayout() | ||||||
|  |         self.command_log_output = QTextEdit() | ||||||
|  |         self.command_log_output.setReadOnly(True) | ||||||
|  |         self.command_log_output.setFont(QFont('DejaVu Sans Mono', 10)) | ||||||
|  |         layout.addWidget(self.command_log_output) | ||||||
|  |  | ||||||
|  |         self.command_close_button = QPushButton("Закрыть") | ||||||
|  |         self.command_close_button.setEnabled(False) | ||||||
|  |         self.command_close_button.clicked.connect(self.command_dialog.close) | ||||||
|  |         layout.addWidget(self.command_close_button) | ||||||
|  |         self.command_dialog.setLayout(layout) | ||||||
|  |  | ||||||
|  |         self.command_process = QProcess(self.command_dialog) | ||||||
|  |         self.command_process.setProcessChannelMode(QProcess.MergedChannels) | ||||||
|  |         self.command_process.readyReadStandardOutput.connect(self._handle_command_output) | ||||||
|  |         self.command_process.finished.connect(self._handle_launcher_creation_finished) | ||||||
|  |  | ||||||
|  |         env = QProcessEnvironment.systemEnvironment() | ||||||
|  |         env.insert("WINEPREFIX", prefix_path) | ||||||
|  |         self.command_process.setProcessEnvironment(env) | ||||||
|  |  | ||||||
|  |         args = ["desktop", app_name, exe_path, "auto"] | ||||||
|  |  | ||||||
|  |         self.command_log_output.append(f"Выполнение: {shlex.quote(self.winehelper_path)} {' '.join(shlex.quote(a) for a in args)}") | ||||||
|  |         self.command_process.start(self.winehelper_path, args) | ||||||
|  |         self.command_dialog.exec_() | ||||||
|  |  | ||||||
|     def create_help_tab(self): |     def create_help_tab(self): | ||||||
|         """Создает вкладку 'Справка' с подвкладками""" |         """Создает вкладку 'Справка' с подвкладками""" | ||||||
|         help_tab = QWidget() |         help_tab = QWidget() | ||||||
| @@ -2503,6 +2632,7 @@ class WineHelperGUI(QMainWindow): | |||||||
|         """Обрабатывает завершение установки в префикс.""" |         """Обрабатывает завершение установки в префикс.""" | ||||||
|         if exit_code == 0: |         if exit_code == 0: | ||||||
|             self.command_log_output.append("\n=== Установка успешно завершена ===") |             self.command_log_output.append("\n=== Установка успешно завершена ===") | ||||||
|  |             self.create_launcher_button.setEnabled(True)  # Активируем кнопку создания ярлыка | ||||||
|         else: |         else: | ||||||
|             self.command_log_output.append(f"\n=== Ошибка выполнения (код: {exit_code}) ===") |             self.command_log_output.append(f"\n=== Ошибка выполнения (код: {exit_code}) ===") | ||||||
|  |  | ||||||
| @@ -2962,6 +3092,9 @@ class WineHelperGUI(QMainWindow): | |||||||
|                 except Exception as e: |                 except Exception as e: | ||||||
|                     raise RuntimeError(f"Ошибка удаления префикса: {str(e)}") |                     raise RuntimeError(f"Ошибка удаления префикса: {str(e)}") | ||||||
|  |  | ||||||
|  |                 # Обновляем состояние на вкладке "Создать префикс" | ||||||
|  |                 self._remove_prefix_from_gui_state(prefix_name) | ||||||
|  |  | ||||||
|                 # 3. Удаляем ВСЕ найденные .desktop файлы, связанные с этим префиксом |                 # 3. Удаляем ВСЕ найденные .desktop файлы, связанные с этим префиксом | ||||||
|                 removed_files = [] |                 removed_files = [] | ||||||
|                 for file_path in all_desktop_files: |                 for file_path in all_desktop_files: | ||||||
| @@ -3514,6 +3647,18 @@ class WineHelperGUI(QMainWindow): | |||||||
|             self.command_process = None |             self.command_process = None | ||||||
|         self.command_close_button.setEnabled(True) |         self.command_close_button.setEnabled(True) | ||||||
|  |  | ||||||
|  |     def _handle_launcher_creation_finished(self, exit_code, exit_status): | ||||||
|  |         """Обрабатывает завершение создания ярлыка.""" | ||||||
|  |         self._handle_command_finished(exit_code, exit_status) | ||||||
|  |         if exit_code == 0: | ||||||
|  |             QMessageBox.information(self, "Успех", "Ярлык успешно создан.") | ||||||
|  |             self.update_installed_apps() | ||||||
|  |             # Переключаемся на вкладку "Установленные" | ||||||
|  |             for i in range(self.tab_bar.count()): | ||||||
|  |                 if self.tab_bar.tabText(i) == "Установленные": | ||||||
|  |                     self.tab_bar.setCurrentIndex(i) | ||||||
|  |                     break | ||||||
|  |  | ||||||
|     def _handle_restore_finished(self, exit_code, exit_status): |     def _handle_restore_finished(self, exit_code, exit_status): | ||||||
|         """Обрабатывает завершение для диалога команды восстановления.""" |         """Обрабатывает завершение для диалога команды восстановления.""" | ||||||
|         if exit_code == 0: |         if exit_code == 0: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user