forked from CastroFidel/winehelper
		
	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 BASE_PFX="tflex17_pfx_x64_v02" | ||||
| export WINEARCH="win64" | ||||
| export WINEPREFIX="tflex17" | ||||
| export WINEPREFIX="tflex" | ||||
| export PROG_VERSION="" | ||||
| 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" | ||||
|   | ||||
							
								
								
									
										152
									
								
								winehelper
									
									
									
									
									
								
							
							
						
						
									
										152
									
								
								winehelper
									
									
									
									
									
								
							| @@ -190,7 +190,7 @@ su_run () { | ||||
|             ((i++)) | ||||
|         done | ||||
|     else | ||||
|         pkexec "$@" && return 0 | ||||
|         pkexec bash -c "$@" && return 0 | ||||
|     fi | ||||
|     fatal "Не удалось установить необходимые компоненты!" | ||||
| } | ||||
| @@ -509,63 +509,29 @@ var_ld_library_path_update () { | ||||
|     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 () { | ||||
|     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" | ||||
|     exe_file="$2" | ||||
|     if [[ -n $4 ]] && [[ $4 != "nocopy" ]]; | ||||
|     then desktop_filename="$4" | ||||
|     else desktop_filename="$(basename "$exe_file" .exe | sed "s| |_|")" | ||||
|     fi | ||||
|     if [[ "$RESTORE_FROM_BACKUP" == "1" ]] && [[ -f "$3" ]] | ||||
|     then icon_file="$3" | ||||
|     elif [[ -f "$WH_IMAGE_PATH/$3.png" ]] | ||||
|     then icon_file="$WH_IMAGE_PATH/$3.png" | ||||
|     else icon_file="wine" | ||||
|     icon_arg="$3" | ||||
|     desktop_filename_arg="$4" | ||||
|  | ||||
|     # Определяем имя desktop-файла | ||||
|     if [[ -n "$desktop_filename_arg" ]] && [[ "$desktop_filename_arg" != "nocopy" ]]; then | ||||
|         desktop_filename="$desktop_filename_arg" | ||||
|     else | ||||
|         desktop_filename="$(basename "$exe_file" .exe | sed "s| |_|g")" | ||||
|     fi | ||||
|  | ||||
|     # Проверяем обязательные аргументы и наличие exe-файла | ||||
|     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 | ||||
|         print_warning "Для создания ярлыка не найден исполняемый файл: $exe_file" | ||||
|  | ||||
|         BASENAME_EXE="$(basename "$exe_file")" | ||||
|         local BASENAME_EXE="$(basename "$exe_file")" | ||||
|         print_info "Запускаем поиск $BASENAME_EXE" | ||||
|         local FIND_PATH | ||||
|         if [[ -z "$DRIVE_C" ]] || [[ ! -d "$DRIVE_C" ]] | ||||
|         then FIND_PATH="$WH_PREFIXES_DIR" | ||||
|         else FIND_PATH="$DRIVE_C" | ||||
| @@ -575,11 +541,55 @@ create_desktop () { | ||||
|                     -iname "$BASENAME_EXE")" | ||||
|         if [[ -z "$exe_file" ]] || [[ ! -f "$exe_file" ]] | ||||
|         then fatal "Для создания ярлыка не найден исполняемый файл: $BASENAME_EXE" | ||||
|         else print_ok "Исполняемый файл $BASENAME_EXE найден по пути $(dirname "$exe_file")/" | ||||
|         else print_ok "Исполняемый файл $BASENAME_EXE найден по пути: $(dirname "$exe_file")/" | ||||
|         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" | ||||
|     { | ||||
|         echo "[Desktop Entry]" | ||||
| @@ -596,19 +606,29 @@ create_desktop () { | ||||
|     cp -f "$USER_WORK_PATH/$desktop_filename.desktop" "$WH_MENU_DIR/" | ||||
|  | ||||
|     if [[ "$RESTORE_FROM_BACKUP" == "1" ]] ; then | ||||
|         print_info "Пропускаем обновление desktop.list (режим восстановления из бэкапа)" | ||||
|         print_info "Пропускаем обновление desktop.list (режим восстановления)" | ||||
|     else | ||||
|         # добавляем информацию о приложении в "$WINEPREFIX/desktop.list" | ||||
|         # Добавляем информацию о приложении в "$WINEPREFIX/desktop.list" | ||||
|         if [[ -f "$WINEPREFIX/desktop.list" ]] \ | ||||
|         && grep -qe "^${name_desktop}=" "$WINEPREFIX/desktop.list" | ||||
|         then sed -i "/^$name_desktop=/d" "$WINEPREFIX/desktop.list" | ||||
|         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 | ||||
|  | ||||
|     # Создаем файл категории для меню | ||||
|     create_new_dir "$HOME/.local/share/desktop-directories" | ||||
|     if [[ ! -f "$WH_MENU_CATEGORY" ]] ; then | ||||
|     cat > "$WH_MENU_CATEGORY" <<EOF | ||||
| @@ -619,7 +639,7 @@ Icon=wine | ||||
| EOF | ||||
|     fi | ||||
|  | ||||
|     # Создаем файл меню для всех приложений | ||||
|     # Создаем файл меню для всех приложений WineHelper | ||||
|     create_new_dir "$HOME/.config/menus/applications-merged" | ||||
|     if [[ ! -f "$WH_MENU_CONFIG" ]] ; then | ||||
|     cat > "$WH_MENU_CONFIG" <<EOF | ||||
| @@ -638,15 +658,15 @@ EOF | ||||
| EOF | ||||
|     fi | ||||
|  | ||||
|     # Обновляем кэш desktop файлов | ||||
|     # Обновляем кэш desktop-файлов | ||||
|     update-desktop-database "$HOME/.local/share/applications" | ||||
|  | ||||
|     if [[ $4 != "nocopy" ]] ; then | ||||
|     if [[ "$desktop_filename_arg" != "nocopy" ]] ; then | ||||
|         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" | ||||
|     else | ||||
|         print_info "В меню создан $desktop_filename.desktop" | ||||
|         print_info "В меню создан ярлык: $desktop_filename.desktop" | ||||
|     fi | ||||
|  | ||||
|     if [[ -n "$INSTALL_SCRIPT_NAME" ]] \ | ||||
| @@ -2044,6 +2064,16 @@ case "$arg1" in | ||||
|     *) | ||||
|         if [[ -f "$arg1" ]] ; then | ||||
|             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")" | ||||
|             case "${WIN_FILE_NAME,,}" in | ||||
|                 *.exe) prepair_wine ; wine_run $WINE_WIN_START "$WIN_FILE_EXEC" "$@" ;; | ||||
|   | ||||
| @@ -12,7 +12,7 @@ import hashlib | ||||
| from functools import partial | ||||
| from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,QPushButton, QLabel, QTabWidget, QTabBar, | ||||
|                              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.QtGui import QIcon, QFont, QTextCursor, QPixmap, QPainter, QDesktopServices | ||||
| from PyQt5.QtNetwork import QLocalServer, QLocalSocket | ||||
| @@ -965,7 +965,8 @@ class ScriptParser: | ||||
|                             if part == 'create_desktop': | ||||
|                                 if len(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) | ||||
|                     except (ValueError, IndexError): | ||||
|                         continue | ||||
| @@ -1975,7 +1976,7 @@ class WineHelperGUI(QMainWindow): | ||||
|  | ||||
|         install_path_layout = QHBoxLayout() | ||||
|         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) | ||||
|  | ||||
|         self.prefix_browse_button = QPushButton("Обзор...") | ||||
| @@ -1983,10 +1984,21 @@ class WineHelperGUI(QMainWindow): | ||||
|         install_path_layout.addWidget(self.prefix_browse_button) | ||||
|         install_layout.addLayout(install_path_layout) | ||||
|  | ||||
|         # Layout для кнопок установки и создания ярлыка | ||||
|         action_buttons_layout = QHBoxLayout() | ||||
|  | ||||
|         self.prefix_install_button = QPushButton("Установить приложение в префикс") | ||||
|         self.prefix_install_button.setEnabled(False) | ||||
|         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) | ||||
|  | ||||
| @@ -2001,6 +2013,19 @@ class WineHelperGUI(QMainWindow): | ||||
|         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) | ||||
|  | ||||
|     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): | ||||
|         """Загружает последнее состояние GUI из файла.""" | ||||
|         if not os.path.exists(self.state_file): | ||||
| @@ -2075,31 +2100,59 @@ class WineHelperGUI(QMainWindow): | ||||
|         msg_box.setIcon(QMessageBox.Question) | ||||
|         msg_box.setWindowTitle('Подтверждение удаления') | ||||
|         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) | ||||
|         msg_box.setDefaultButton(no_button) | ||||
|  | ||||
|         msg_box.exec_() | ||||
|  | ||||
|         # Если пользователь нажал не "Да", выходим | ||||
|         if msg_box.clickedButton() != yes_button: | ||||
|             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: | ||||
|             if os.path.isdir(prefix_path): | ||||
|                 shutil.rmtree(prefix_path) | ||||
|             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) | ||||
|             QMessageBox.information(self, "Успех", f"Префикс '{prefix_name}' был успешно удален.") | ||||
|         except Exception as e: | ||||
|             QMessageBox.critical(self, "Ошибка удаления", f"Не удалось удалить префикс '{prefix_name}':\n{e}") | ||||
|         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( | ||||
|             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): | ||||
|         """Сбрасывает состояние управления префиксом, когда пользователь вводит новое имя.""" | ||||
| @@ -2116,6 +2169,9 @@ class WineHelperGUI(QMainWindow): | ||||
|             self.prefix_management_groupbox.setEnabled(False) | ||||
|             self.prefix_info_display.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() | ||||
|  | ||||
|     def update_prefix_info_display(self, prefix_name): | ||||
| @@ -2197,6 +2253,79 @@ class WineHelperGUI(QMainWindow): | ||||
|         self.command_process.start(wine_executable, args) | ||||
|         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): | ||||
|         """Создает вкладку 'Справка' с подвкладками""" | ||||
|         help_tab = QWidget() | ||||
| @@ -2503,6 +2632,7 @@ class WineHelperGUI(QMainWindow): | ||||
|         """Обрабатывает завершение установки в префикс.""" | ||||
|         if exit_code == 0: | ||||
|             self.command_log_output.append("\n=== Установка успешно завершена ===") | ||||
|             self.create_launcher_button.setEnabled(True)  # Активируем кнопку создания ярлыка | ||||
|         else: | ||||
|             self.command_log_output.append(f"\n=== Ошибка выполнения (код: {exit_code}) ===") | ||||
|  | ||||
| @@ -2962,6 +3092,9 @@ class WineHelperGUI(QMainWindow): | ||||
|                 except Exception as e: | ||||
|                     raise RuntimeError(f"Ошибка удаления префикса: {str(e)}") | ||||
|  | ||||
|                 # Обновляем состояние на вкладке "Создать префикс" | ||||
|                 self._remove_prefix_from_gui_state(prefix_name) | ||||
|  | ||||
|                 # 3. Удаляем ВСЕ найденные .desktop файлы, связанные с этим префиксом | ||||
|                 removed_files = [] | ||||
|                 for file_path in all_desktop_files: | ||||
| @@ -3514,6 +3647,18 @@ class WineHelperGUI(QMainWindow): | ||||
|             self.command_process = None | ||||
|         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): | ||||
|         """Обрабатывает завершение для диалога команды восстановления.""" | ||||
|         if exit_code == 0: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user