Compare commits

...

14 Commits

Author SHA1 Message Date
Sergey Palcheh
4afdbaa220 added the winetricks cache deletion feature 2025-10-25 15:16:09 +06:00
Sergey Palcheh
81013bfe71 fix: reset active button if it's being removed 2025-10-25 12:31:16 +06:00
Sergey Palcheh
caccc333db updating tax program scripts 2025-10-25 12:26:42 +06:00
Mikhail Tergoev
151d0ffc48 Merge branch 'minergenon-devel' 2025-10-23 11:11:50 +03:00
Mikhail Tergoev
ad91466475 updated print message functions 2025-10-23 11:11:18 +03:00
Sergey Palcheh
5e4d94bb57 temporarily disable the display of the tray icon 2025-10-23 14:02:50 +06:00
Sergey Palcheh
5b572ff540 added a change in the color of the tray icon depending on the theme 2025-10-23 14:00:20 +06:00
Sergey Palcheh
c68bcc9abf added a method to change the color of the tray icon 2025-10-23 12:38:10 +06:00
Sergey Palcheh
1ad2c6cfa8 The Manual sub-tab has been renamed to General 2025-10-23 11:31:43 +06:00
Sergey Palcheh
16a686dc37 added a new file with general information 2025-10-23 11:30:37 +06:00
Mikhail Tergoev
c9d5619ab9 used simply wine_run for .reg files 2025-10-22 15:16:22 +03:00
Mikhail Tergoev
74311e9c04 fixed: remove OUT_PAGE_TMP after use install scripts 2025-10-22 15:14:57 +03:00
Sergey Palcheh
eb9bef83e2 improved display of test versions 2025-10-22 11:13:55 +06:00
Sergey Palcheh
c7eddb8b53 tray icon changed to winehelper-symbolic.svg 2025-10-22 09:25:19 +06:00
11 changed files with 312 additions and 132 deletions

7
GENERAL Normal file
View File

@@ -0,0 +1,7 @@
# Руководство пользователя
Подробное и актуальное руководство по использованию WineHelper смотрите на сайте: https://www.altlinux.org/Winehelper
# Совместимость ПО и сертификаты
С полным списком совместимого ПО и сертификатами можно ознакомиться по следующим ссылкам:
Для 10 платформы: https://www.basealt.ru/fileadmin/user_upload/compatibility/P10-view2.html
Для 11 платформы: https://www.basealt.ru/fileadmin/user_upload/compatibility/P11-view2.html

View File

@@ -4,7 +4,7 @@ _winehelper_completions() {
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts="--help --version --debug install installed install-dxvk install-vkd3d -r -i remove-all --clear-pfx killall remove-prefix backup-prefix restore-prefix create-prefix --changelog changelog change-wine"
opts="--help --version --debug install installed install-dxvk install-vkd3d -r -i remove-all --clear-pfx killall remove-prefix backup-prefix restore-prefix create-prefix --changelog changelog change-wine clear-winetricks-cache"
wine_cmd="winecfg winereg winefile wineconsole winetricks desktop regedit explorer cmd run"
case "${prev}" in

View File

@@ -21,6 +21,7 @@ _winehelper() {
'backup-prefix[Создать резерную копию префикса]'
'restore-prefix[восстановить префикс из резервной копии "путь/до/whpack"]'
'change-wine[Изменить версию Wine/Proton для префикса]'
'clear-winetricks-cache[Очистить кэш Winetricks]'
)
wine_cmd=(

View File

@@ -3,37 +3,33 @@
########################################################################
export PROG_URL="https://www.nalog.gov.ru"
export WH_WINE_USE="wine_x_tkg_10-0_amd64"
export WINEPREFIX="declaration"
export WINEPREFIX="nalog"
export PROG_NAME="Декларация"
export PROG_ICON="declarac"
export BASE_PFX="defpfx_x86_v01"
export BASE_PFX="none"
export WINEARCH="win32"
export INSTALL_DLL="msxml3 msxml4 msxml6 corefonts wsh57 vcrun6 jet40 gdiplus"
export WH_WINDOWS_VER="10"
export INSTALL_DLL="corefonts micross tahoma lucida riched20 comctl32 msxml3 msxml4 msxml6 mdac28 wsh57 vcrun6 vb6run jet40 gdiplus vcrun2019 dotnet20sp2 dotnet40 dotnet48"
DECL_FILE="${WH_TMP_DIR}/decl.html"
curl -o "$DECL_FILE" -A "Mozilla/5.0 (compatible; Konqueror/2.1.1; X11)" "https://www.nalog.gov.ru/rn77/program/5961249/"
if [[ ! -f "$DECL_FILE" ]] \
|| grep -q "Forbidden" "$DECL_FILE"
then
fatal "The site page is unavailable or the request limit has been exceeded."
fi
VER_YEAR=$(grep -oP 'href="\K[^"]*.msi[^"]*' "$DECL_FILE" | awk -F'/' '{print $(NF-2)}' | head -n 1)
try_get_page "https://www.nalog.gov.ru/rn77/program/5961249/"
VER_YEAR=$(read_page | grep -oP 'href="\K[^"]*.msi[^"]*' | awk -F'/' '{print $(NF-2)}' | head -n 1)
YEAR="${VER_YEAR//decl/}"
VER_MSI_SLASH=$(grep -oP 'href="\K[^"]*.msi[^"]*' "$DECL_FILE" | awk -F'/' '{print $(NF-1)}' | head -n 1)
VER_MSI=$(grep -oP 'href="\K[^"]*.msi[^"]*' "$DECL_FILE" | awk -F'/' '{print $(NF)}' | head -n 1)
VER_MSI_SLASH=$(read_page | grep -oP 'href="\K[^"]*.msi[^"]*' | awk -F'/' '{print $(NF-1)}' | head -n 1)
VER_MSI=$(read_page | grep -oP 'href="\K[^"]*.msi[^"]*' | awk -F'/' '{print $(NF)}' | head -n 1)
AUTOINSTALL_MSI="${WH_TMP_DIR}/${VER_MSI}"
prepair_wine
if try_download "https://data.nalog.ru/files/${VER_YEAR}/${VER_MSI_SLASH}/$VER_MSI" "${AUTOINSTALL_MSI}" ; then
wine_run_install "${AUTOINSTALL_MSI}" "/q"
if try_download "https://data.nalog.ru/files/${VER_YEAR}/${VER_MSI_SLASH}/${VER_MSI}" "${AUTOINSTALL_MSI}" ; then
wine_run_install "${AUTOINSTALL_MSI}" /q
try_remove_file "${AUTOINSTALL_MSI}"
WIN_FILE_EXEC="$DRIVE_C/АО ГНИВЦ/Декларация ${YEAR}/Decl${YEAR}.exe"
create_desktop "$PROG_NAME $YEAR" "$WIN_FILE_EXEC" "$PROG_ICON"
remove_desktop "Декларация $((YEAR - 1))"
fi
# Удаляем ярлык предыдущей версии
remove_desktop "Декларация $((YEAR - 1))"
print_info "Программа Декларация $YEAR успешно установлена"
else
fatal "Не удалось скачать установочный файл"
fi

View File

@@ -6,32 +6,24 @@ export WH_WINE_USE="wine_x_tkg_10-0_amd64"
export WINEPREFIX="nalog"
export PROG_NAME="Налогоплательщик ЮЛ"
export PROG_ICON="npul"
export BASE_PFX="defpfx_x86_v01"
export BASE_PFX="none"
export WINEARCH="win32"
export INSTALL_DLL="msxml3 msxml4 msxml6 corefonts wsh57 vcrun6 jet40 gdiplus"
export WH_WINDOWS_VER="10"
export INSTALL_DLL="corefonts micross tahoma lucida riched20 comctl32 msxml3 msxml4 msxml6 mdac28 wsh57 vcrun6 vb6run jet40 gdiplus vcrun2019 dotnet20sp2 dotnet40 dotnet48"
NPUL_FILE="${WH_TMP_DIR}/npul.html"
curl -o "$NPUL_FILE" -A "Mozilla/5.0 (compatible; Konqueror/2.1.1; X11)" "https://www.nalog.gov.ru/rn77/program/5961229/"
if [[ ! -f "$NPUL_FILE" ]] \
|| grep -q "Forbidden" "$NPUL_FILE"
then
fatal "Страница сайта не доступна, или превышено количество запросов к странице."
fi
VER_MSI=$(grep -oP 'NalogUL\K[0-9.]+(?=\.msi)' "$NPUL_FILE" | tail -n 1)
VER_MSI_SLASH=$(grep -oP '[0-9]+\.[0-9]+/NalogUL[0-9]+\.msi' "$NPUL_FILE" | tail -n 1)
VER_EXE=$(grep -oP 'NalogUL\K[0-9.]+(?=\.exe)' "$NPUL_FILE" | tail -n 1)
VER_EXE_SLASH=$(grep -oP '[0-9]+\.[0-9]+\.[0-9]+/NalogUL[0-9]+\.exe' "$NPUL_FILE" | tail -n 1)
try_get_page "https://data.nalog.ru/rn77/program/5961229/"
VER_MSI=$(read_page | grep -oP 'NalogUL\d+\.msi' | tail -1 | grep -oP '\d+')
VER_MSI_URL="${VER_MSI:0:1}.${VER_MSI:1}" # 492 → 4.92
VER_EXE=$(read_page | grep -oP 'NalogUL\d+\.exe' | tail -1 | grep -oP '\d+')
VER_EXE_URL="${VER_EXE:0:1}.${VER_EXE:1:2}.${VER_EXE:3}" # 4924 → 4.92.4
AUTOINSTALL_MSI="${WH_TMP_DIR}/NalogUL${VER_MSI}.msi"
AUTOINSTALL_EXE="${WH_TMP_DIR}/NalogUL${VER_EXE}.exe"
prepair_wine
if try_download "https://data.nalog.ru/files/nalul/${VER_MSI_SLASH}" "${AUTOINSTALL_MSI}" ; then
if try_download "https://data.nalog.ru/files/nalul/${VER_MSI_URL}/NalogUL${VER_MSI}.msi" "${AUTOINSTALL_MSI}" ; then
wine_run_install "${AUTOINSTALL_MSI}" /quiet INSTALLDIR="c:\npul"
try_remove_file "${AUTOINSTALL_MSI}"
try_remove_file "${AUTOINSTALL_MSI}"
PRINT_INSTALLER="$(find "$DRIVE_C/npul/INPUTDOC" -name "*.msi")"
wine_run_install "${PRINT_INSTALLER}" "/q"
@@ -42,7 +34,7 @@ if try_download "https://data.nalog.ru/files/nalul/${VER_MSI_SLASH}" "${AUTOINST
fi
if [[ -n "$VER_EXE" ]] \
&& try_download "https://data.nalog.ru/files/nalul/${VER_EXE_SLASH}" "${AUTOINSTALL_EXE}"
&& try_download "https://data.nalog.ru/files/nalul/${VER_EXE_URL}/NalogUL${VER_EXE}.exe" "${AUTOINSTALL_EXE}"
then
wine_run_install "${AUTOINSTALL_EXE}" "/SILENT"
try_remove_file "${AUTOINSTALL_EXE}"
@@ -53,4 +45,3 @@ fi
touch "$DRIVE_C/npul/INPUTDOC/linux.txt"
WIN_FILE_EXEC="$DRIVE_C/npul/INPUTDOC/inputdoc.exe"
create_desktop "$PROG_NAME" "$WIN_FILE_EXEC" "$PROG_ICON"
try_remove_file "$NPUL_FILE"

View File

@@ -2,24 +2,26 @@
# info_ru: Подготовка документов для государственной регистрации (ППДГР)
########################################################################
export PROG_URL="https://www.nalog.gov.ru"
export AUTOINSTALL_EXE="${WH_TMP_DIR}/SetupPPDGR2.msi"
export WH_WINE_USE="wine_x_tkg_10-0_amd64"
export WINEPREFIX="ppdgr2"
export WINEPREFIX="nalog"
export PROG_NAME="ППДГР-2"
# export PROG_VERSION=""
export PROG_ICON="ppdgr"
# export ADD_MIME_TYPE=""
export BASE_PFX="defpfx_dn48_x86_v01"
export BASE_PFX="none"
export WINEARCH="win32"
export INSTALL_DLL="dotnet48 msxml3 msxml4 msxml6 corefonts lucida wsh57 vcrun6 jet40 gdiplus"
export WH_WINDOWS_VER="10"
var_winedlloverride_update "msxml4=b,wininet=b"
export INSTALL_DLL="corefonts micross tahoma lucida riched20 comctl32 msxml3 msxml4 msxml6 mdac28 wsh57 vcrun6 vb6run jet40 gdiplus vcrun2019 dotnet20sp2 dotnet40 dotnet48"
try_get_page "https://www.nalog.gov.ru/rn77/program/5961277/"
VER_MSI_SLASH=$(read_page | grep -oP 'href="\K[^"]*.msi[^"]*' | awk -F'/' '{print $(NF-1)}' | head -n 1)
AUTOINSTALL_EXE="${WH_TMP_DIR}/SetupPPDGR2.msi"
prepair_wine
if try_download "https://data.nalog.ru/files/ppdgr/2.7.0/SetupPPDGR2.msi" "${AUTOINSTALL_EXE}" ; then
if try_download "https://data.nalog.ru/files/ppdgr/${VER_MSI_SLASH}/SetupPPDGR2.msi" "${AUTOINSTALL_EXE}" ; then
wine_run_install "${AUTOINSTALL_EXE}" /q
try_remove_file "${AUTOINSTALL_EXE}"
WIN_FILE_EXEC="$DRIVE_C/АО ГНИВЦ/ППДГР-2/PPDGR2.exe"
create_desktop "$PROG_NAME" "$WIN_FILE_EXEC" "$PROG_ICON"
fi
https://data.nalog.ru/files/ppdgr/2.7.3/SetupPPDGR2.msi

View File

@@ -44,13 +44,13 @@ ADDONS_PATH_OPENSSH="${ADDONS_PATH}/OpenSSH"
if try_download "$SCADOFFICE_ADDONS_URL" "${ADDONS_PACK}" ; then
create_new_dir "${ADDONS_PATH}"
unpack "${ADDONS_PACK}" "${ADDONS_PATH}"
wine_run regedit "${ADDONS_PATH_REG}"/*.reg
wine_run "${ADDONS_PATH_REG}"/*.reg
# Установка ODBC
rm -fR "$DRIVE_C/Program Files (x86)/Common Files/System"
cp -r "${ADDONS_PATH_MDAC}/System" "$DRIVE_C/Program Files (x86)/Common Files/System"
cp -r "${ADDONS_PATH_MDAC}"/*.* "$DRIVE_C/windows/system32/"
wine_run regedit "${ADDONS_PATH_MDAC}"/*.reg
wine_run "${ADDONS_PATH_MDAC}"/*.reg
# Установка SSH
cp -r "${ADDONS_PATH_OPENSSH}" "$DRIVE_C/windows/system32/"

View File

@@ -2,20 +2,21 @@
# info_ru: Справочник кодов обозначения налоговых органов для целей учета налогоплательщиков
########################################################################
export PROG_URL="https://www.nalog.gov.ru"
export AUTOINSTALL_EXE="${WH_TMP_DIR}/soun_ins.exe"
export WH_WINE_USE="wine_x_tkg_10-0_amd64"
export WINEPREFIX="soun"
export WINEPREFIX="nalog"
export PROG_NAME="СОУН"
# export PROG_VERSION=""
export PROG_ICON="soun"
# export ADD_MIME_TYPE=""
export BASE_PFX="defpfx_x86_v01"
export BASE_PFX="none"
export WINEARCH="win32"
export INSTALL_DLL="corefonts"
export WH_WINDOWS_VER="10"
export INSTALL_DLL="corefonts micross tahoma lucida riched20 comctl32 msxml3 msxml4 msxml6 mdac28 wsh57 vcrun6 vb6run jet40 gdiplus vcrun2019 dotnet20sp2 dotnet40 dotnet48"
try_get_page "https://www.nalog.gov.ru/rn77/program/5961268/"
VER_MSI_SLASH=$(read_page | grep -oP 'href="\K[^"]*.exe[^"]*' | awk -F'/' '{print $(NF-1)}' | head -n 1)
AUTOINSTALL_EXE="${WH_TMP_DIR}/soun_ins.exe"
prepair_wine
if try_download "https://data.nalog.ru/files/Soun/2.6.2/soun_ins.exe" "${AUTOINSTALL_EXE}" ; then
if try_download "https://data.nalog.ru/files/Soun/${VER_MSI_SLASH}/soun_ins.exe" "${AUTOINSTALL_EXE}" ; then
# TODO: Тихий режим или предупреждение
wine_run_install "${AUTOINSTALL_EXE}"
try_remove_file "${AUTOINSTALL_EXE}"

View File

@@ -2,22 +2,23 @@
# info_ru: Программа проверки файлов на соответствие форматам представления в электронном виде налоговых деклараций, бухгалтерской отчетности.
########################################################################
export PROG_URL="https://www.nalog.gov.ru"
export LAUNCH_PARAMETERS="/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-"
export AUTOINSTALL_EXE="${WH_TMP_DIR}/tester2269.exe"
export WH_WINE_USE="wine_x_tkg_10-0_amd64"
export WINEPREFIX="nalog"
export PROG_NAME="Тестер"
# export PROG_VERSION=""
export PROG_ICON="tester"
# export ADD_MIME_TYPE=""
export BASE_PFX="defpfx_x86_v01"
export BASE_PFX="none"
export WINEARCH="win32"
export INSTALL_DLL="msxml3 msxml4 msxml6 corefonts wsh57 vcrun6 jet40 gdiplus"
export WH_WINDOWS_VER="10"
export INSTALL_DLL="corefonts micross tahoma lucida riched20 comctl32 msxml3 msxml4 msxml6 mdac28 wsh57 vcrun6 vb6run jet40 gdiplus vcrun2019 dotnet20sp2 dotnet40 dotnet48"
try_get_page "https://www.nalog.gov.ru/rn77/program/5961279/"
VER_EXE_SLASH=$(read_page | grep -oP 'href="\K[^"]*.exe[^"]*' | awk -F'/' '{print $(NF-1)}' | tail -n 1)
VER_EXE=$(read_page | grep -oP 'href="\K[^"]*.exe[^"]*' | awk -F'/' '{print $(NF)}' | tail -n 1)
AUTOINSTALL_EXE="${WH_TMP_DIR}/${VER_EXE}"
prepair_wine
if try_download "https://data.nalog.ru/files/tester/2.269/tester2269.exe" "${AUTOINSTALL_EXE}" ; then
wine_run_install "${AUTOINSTALL_EXE}"
if try_download "https://data.nalog.ru/files/tester/${VER_EXE_SLASH}/${VER_EXE}" "${AUTOINSTALL_EXE}" ; then
wine_run_install "${AUTOINSTALL_EXE}" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-
try_remove_file "${AUTOINSTALL_EXE}"
WIN_FILE_EXEC="$DRIVE_C/Tester/tester.exe"

View File

@@ -7,7 +7,7 @@ if [[ $(id -u) -eq 0 ]] ; then
fi
##### DEFAULT PATH #####
export SCRIPT_NAME USER_WORK_PATH RUN_SCRIPT DATA_PATH CHANGELOG_FILE WH_ICON_PATH LICENSE_FILE AGREEMENT THIRD_PARTY_FILE
export SCRIPT_NAME USER_WORK_PATH RUN_SCRIPT DATA_PATH CHANGELOG_FILE WH_ICON_PATH LICENSE_FILE AGREEMENT THIRD_PARTY_FILE WH_ICON_TRAY GENERAL
SCRIPT_NAME="$(basename "$0")"
if [[ "$(realpath "$0")" == "/usr/bin/$SCRIPT_NAME" ]] ; then
@@ -17,11 +17,12 @@ if [[ "$(realpath "$0")" == "/usr/bin/$SCRIPT_NAME" ]] ; then
RUN_SCRIPT="/usr/bin/$SCRIPT_NAME"
DATA_PATH="/usr/share/$SCRIPT_NAME"
WH_ICON_PATH="/usr/share/icons/hicolor/scalable/apps/winehelper.svg"
WH_ICON_TRAY=" /usr/share/icons/hicolor/symbolic/apps/winehelper-symbolic.svg"
WH_ICON_TRAY="/usr/share/icons/hicolor/symbolic/apps/winehelper-symbolic.svg"
CHANGELOG_FILE="/usr/share/doc/winehelper-$WH_VERSION/CHANGELOG"
LICENSE_FILE="/usr/share/doc/winehelper-$WH_VERSION/LICENSE"
AGREEMENT="/usr/share/doc/winehelper-$WH_VERSION/LICENSE_AGREEMENT"
THIRD_PARTY_FILE="/usr/share/doc/winehelper-$WH_VERSION/THIRD-PARTY"
GENERAL="/usr/share/doc/winehelper-$WH_VERSION/GENERAL"
else
# переменные для тестового запуска WineHelper из репозитория
USER_WORK_PATH="$HOME/test-$SCRIPT_NAME"
@@ -33,6 +34,7 @@ else
LICENSE_FILE="$DATA_PATH/LICENSE"
AGREEMENT="$DATA_PATH/LICENSE_AGREEMENT"
THIRD_PARTY_FILE="$DATA_PATH/THIRD-PARTY"
GENERAL="$DATA_PATH/GENERAL"
WH_DEVEL="1"
# минимальная проверка синтаксиса скриптов
@@ -52,21 +54,21 @@ fi
##### MESSAGES FUNCTIONS #####
if [[ $WH_USE_GUI != "1" ]] ; then
print_error () { printf "\E[31m%s Ошибка: $@ %s\e[0m\n" ;}
print_warning () { printf "\E[33m%s Предупреждение: $@ %s\e[0m\n" ;}
print_info () { printf "\E[36m%s Информация: \"$@\" %s\e[0m\n" ;}
print_ok () { printf "\E[35m%s Успех: $@ %s\e[0m\n" ;}
print_error () { printf "\E[31m%s Ошибка: $* %s\e[0m\n" ;}
print_warning () { printf "\E[33m%s Предупреждение: $* %s\e[0m\n" ;}
print_info () { printf "\E[36m%s Информация: \"$*\" %s\e[0m\n" ;}
print_ok () { printf "\E[35m%s Успех: $* %s\e[0m\n" ;}
else
print_error () { echo -e "Ошибка: $@" ;}
print_warning () { echo -e "Предупреждение: $@" ;}
print_info () { echo -e "Информация: \"$@\"" ;}
print_ok () { echo -e "Успех: $@" ;}
print_error () { echo -e "Ошибка: $*" ;}
print_warning () { echo -e "Предупреждение: $*" ;}
print_info () { echo -e "Информация: \"$*\"" ;}
print_ok () { echo -e "Успех: $*" ;}
fi
print_var () { for vp in $@ ; do echo "${vp}=${!vp}" ; done ;}
fatal () {
print_error "$@"
print_error "$@ Аварийное завершение работы WineHelper!"
[[ -n "$WINESERVER" ]] && "$WINESERVER" -w
exit 1
}
@@ -326,6 +328,7 @@ unpack () {
try_get_page () {
local url_page="$1"
export OUT_PAGE_TMP="${WH_TMP_DIR}/url_page.tmp"
try_remove_file "$OUT_PAGE_TMP"
print_info "Чтение страницы: $url_page"
if ! curl -o "$OUT_PAGE_TMP" -A "Mozilla/5.0 (compatible; Konqueror/2.1.1; X11)" "$url_page" \
|| grep -q "Forbidden" "$OUT_PAGE_TMP"
@@ -342,7 +345,6 @@ read_page () {
&& [[ -f "$OUT_PAGE_TMP" ]]
then
cat "$OUT_PAGE_TMP"
try_remove_file "$OUT_PAGE_TMP"
unset OUT_PAGE_TMP
else
echo "Используй try_get_page перед read_page"
@@ -1539,6 +1541,7 @@ run_autoinstall () {
else print_license_agreement
fi
source "$INSTALL_SCRIPT" "$@"
[[ -n $OUT_PAGE_TMP ]] && try_remove_file "$OUT_PAGE_TMP"
print_info "Завершена установка $INSTALL_SCRIPT_NAME"
else
fatal "Скрипт автоматической установки для $INSTALL_SCRIPT_NAME не найден!"
@@ -2290,6 +2293,30 @@ run_change_wine_version() {
print_ok "Версия Wine для префикса $PREFIX_NAME успешно изменена на $WH_WINE_USE."
}
clear_winetricks_cache() {
local winetricks_cache_dir="$HOME/.cache/winetricks"
local winehelper_wt_cache_dir="$HOME/.cache/winehelper/winetricks"
if [[ ! -d "$winetricks_cache_dir" ]] && [[ ! -d "$winehelper_wt_cache_dir" ]]; then
print_info "Кэш Winetricks не найден. Очистка не требуется."
return 0
fi
if [[ ! $1 =~ --force|-y ]] ; then
print_warning "Вы собираетесь очистить кэш Winetricks."
echo "Будут удалены все скачанные установщики Winetricks и списки компонентов."
if ! print_confirmation "Продолжить?"
then
print_info "Операция отменена."
exit 1
fi
fi
print_info "Очистка кэша Winetricks..."
try_remove_dir "$winetricks_cache_dir"
try_remove_dir "$winehelper_wt_cache_dir"
print_ok "Кэш Winetricks успешно очищен."
}
wh_info () {
echo "Использование: $SCRIPT_NAME [команда]
@@ -2309,6 +2336,7 @@ wh_info () {
remove-prefix [имя_префикса] удалить префикс и все связанные данные
backup-prefix [имя_префикса] создать резервную копию префикса
restore-prefix \"путь/до/whpack\" восстановить префикс из резервной копии
clear-winetricks-cache очистить кэш Winetricks
Параметры:
--help показать эту справку и выйти
@@ -2367,6 +2395,7 @@ case "$arg1" in
remove-prefix) remove_prefix "$@" ;;
create-base-pfx) create_base_pfx "$@" ;;
init-prefix) prepair_wine ; wait_wineserver ;;
clear-winetricks-cache) clear_winetricks_cache "$@" ;;
*)
if [[ -f "$arg1" ]] ; then
WIN_FILE_EXEC="$(readlink -f "$arg1")"

View File

@@ -13,8 +13,8 @@ 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, QInputDialog, QDialogButtonBox, QSystemTrayIcon, QMenu)
from PyQt5.QtCore import Qt, QProcess, QSize, QTimer, QProcessEnvironment, QPropertyAnimation, QEasingCurve, pyqtSignal
from PyQt5.QtGui import QIcon, QFont, QTextCursor, QPixmap, QPainter, QCursor, QTextCharFormat
from PyQt5.QtCore import Qt, QProcess, QSize, QTimer, QProcessEnvironment, QPropertyAnimation, QEasingCurve, pyqtSignal, QRect
from PyQt5.QtGui import QIcon, QFont, QTextCursor, QPixmap, QPainter, QCursor, QTextCharFormat, QColor, QPalette
from PyQt5.QtNetwork import QLocalServer, QLocalSocket
@@ -26,9 +26,11 @@ class Var:
DATA_PATH = os.environ.get("DATA_PATH")
CHANGELOG_FILE = os.environ.get("CHANGELOG_FILE")
WH_ICON_PATH = os.environ.get("WH_ICON_PATH")
WH_ICON_TRAY = os.environ.get("WH_ICON_TRAY")
LICENSE_FILE = os.environ.get("LICENSE_FILE")
LICENSE_AGREEMENT_FILE = os.environ.get("AGREEMENT")
THIRD_PARTY_FILE = os.environ.get("THIRD_PARTY_FILE")
GENERAL = os.environ.get("GENERAL")
class DependencyManager:
"""Класс для управления проверкой и установкой системных зависимостей."""
@@ -444,6 +446,7 @@ class WinetricksManagerDialog(QDialog):
self.previous_tab_widget = None
self.cache_dir = os.path.join(os.path.expanduser("~"), ".cache", "winehelper", "winetricks")
os.makedirs(self.cache_dir, exist_ok=True)
self.is_reloading_after_cache_clear = False
self.setWindowTitle(f"Менеджер компонентов для префикса: {os.path.basename(prefix_path)}")
self.setMinimumSize(800, 500)
@@ -476,8 +479,14 @@ class WinetricksManagerDialog(QDialog):
self.log_output.setText(self.INFO_TEXT)
main_layout.addWidget(self.log_output)
# Кнопки управления, выровненные по правому краю
# Кнопки управления
button_layout = QHBoxLayout()
self.clear_cache_button = QPushButton("Очистить кеш")
self.clear_cache_button.setStyleSheet("background-color: red; color: white;")
self.clear_cache_button.clicked.connect(self.clear_winetricks_cache)
button_layout.addWidget(self.clear_cache_button)
button_layout.addStretch(1)
self.apply_button = QPushButton("Применить")
@@ -734,9 +743,18 @@ class WinetricksManagerDialog(QDialog):
self._log(output)
self._log("--------------------------------------------------")
# Проверяем, были ли ошибки во время загрузки какой-либо из категорий
has_errors = any(status == 'error' for status in self.category_statuses.values())
self.loading_count -= 1
if self.loading_count == 0:
self._update_ui_state()
if self.is_reloading_after_cache_clear:
if has_errors:
self._log("\n=== Ошибка при обновлении списков. Проверьте лог выше. ===", "red")
else:
self._log("\n=== Списки успешно обновлены ===")
self.is_reloading_after_cache_clear = False # Сбрасываем флаг
def _on_item_changed(self, item):
"""Обрабатывает изменение состояния чекбокса, предотвращая снятие галочки с установленных."""
@@ -893,6 +911,64 @@ class WinetricksManagerDialog(QDialog):
self.installation_complete.emit()
self.installation_finished = True
def clear_winetricks_cache(self):
"""Запускает очистку кэша Winetricks."""
reply = self._show_message_box(
"Очистка кэша Winetricks",
"Вы собираетесь удалить все скачанные установщики и списки компонентов Winetricks.\n\n"
"Это действие может потребоваться, если у вас возникают проблемы со скачиванием или установкой компонентов.\n\n"
"Продолжить?",
QMessageBox.Question,
{"buttons": {"Да": QMessageBox.YesRole, "Нет": QMessageBox.NoRole}, "default": "Нет"}
)
if reply != "Да":
return
# Блокируем UI на время выполнения
self.tabs.setEnabled(False)
self.clear_cache_button.setEnabled(False)
self.apply_button.setEnabled(False)
self.reinstall_button.setEnabled(False)
self.close_button.setEnabled(False)
self.log_output.clear()
self.cache_clear_process = QProcess(self)
self.cache_clear_process.setProcessChannelMode(QProcess.MergedChannels)
def handle_output():
output = self.cache_clear_process.readAll().data().decode('utf-8', 'ignore').strip()
if output:
self._log(output)
def handle_finish(exit_code, exit_status):
if exit_code == 0:
self.is_reloading_after_cache_clear = True # Устанавливаем флаг перед перезагрузкой
self.category_statuses.clear() # Очищаем статусы перед новой загрузкой
# Воссоздаем директорию кэша, так как скрипт ее полностью удалил
os.makedirs(self.cache_dir, exist_ok=True)
self._log("Обновление списков...")
self.initial_states.clear()
self.load_all_categories()
else:
self._log(f"\n=== Ошибка (код: {exit_code}) ===", "red")
# Восстанавливаем UI
self.tabs.setEnabled(True)
self.clear_cache_button.setEnabled(True)
self.close_button.setEnabled(True)
self._update_ui_state() # Обновляем состояние кнопок Применить/Переустановить
self.cache_clear_process.readyRead.connect(handle_output)
self.cache_clear_process.finished.connect(handle_finish)
winehelper_path = self.parent().winehelper_path if hasattr(self.parent(), 'winehelper_path') else Var.RUN_SCRIPT
args = ["clear-winetricks-cache", "--force"]
self._log(f"Выполнение: {shlex.quote(winehelper_path)} {' '.join(args)}\n")
self.cache_clear_process.start(winehelper_path, args)
def closeEvent(self, event):
"""Обрабатывает закрытие окна, чтобы предотвратить выход во время установки."""
# Проверяем, запущен ли процесс установки/переустановки
@@ -936,6 +1012,8 @@ class WinetricksManagerDialog(QDialog):
"""Добавляет сообщение в лог с возможностью указания цвета."""
if color:
self.log_output.append(f'<span style="color:{color};">{message}</span>')
# Сбрасываем формат, чтобы следующий текст не наследовал цвет
self.log_output.setCurrentCharFormat(QTextCharFormat())
else:
self.log_output.append(message)
self.log_output.moveCursor(QTextCursor.End)
@@ -1737,6 +1815,18 @@ class WineHelperGUI(QMainWindow):
self.raise_()
self.activateWindow()
def create_colorized_icon(self, icon_path, color):
"""Загружает иконку (SVG) и применяет к ней указанный цвет."""
target_pixmap = QPixmap(icon_path)
if target_pixmap.isNull():
return QIcon()
painter = QPainter(target_pixmap)
painter.setCompositionMode(QPainter.CompositionMode_SourceIn)
painter.fillRect(target_pixmap.rect(), QColor(color))
painter.end()
return QIcon(target_pixmap)
def create_tray_icon(self):
"""Создает и настраивает иконку в системном трее."""
if not QSystemTrayIcon.isSystemTrayAvailable():
@@ -1745,11 +1835,23 @@ class WineHelperGUI(QMainWindow):
self.tray_icon = QSystemTrayIcon(self)
icon_path = Var.WH_ICON_PATH
if icon_path and os.path.exists(icon_path):
pixmap = QPixmap(icon_path)
if not pixmap.isNull():
self.tray_icon.setIcon(QIcon(pixmap))
# --- Определение цвета иконки в зависимости от темы ---
if Var.WH_ICON_TRAY and os.path.exists(Var.WH_ICON_TRAY):
# Получаем цвет текста окна из палитры приложения.
# Это хороший индикатор для определения контрастного цвета.
window_text_color = self.palette().color(QPalette.WindowText)
# Если цвет текста светлый (высокая яркость), значит, тема темная.
# И наоборот: если цвет текста темный, тема светлая.
# Яркость > 127 обычно указывает на светлый цвет.
is_dark_theme = window_text_color.lightness() > 127
if is_dark_theme:
# Для темных тем используем белую иконку
self.tray_icon.setIcon(self.create_colorized_icon(Var.WH_ICON_TRAY, Qt.white))
else:
# Для светлых тем используем черную иконку
self.tray_icon.setIcon(self.create_colorized_icon(Var.WH_ICON_TRAY, Qt.black))
# Создаем и сохраняем меню как атрибут класса, чтобы оно не удалялось
self.tray_menu = QMenu(self)
@@ -1792,10 +1894,7 @@ class WineHelperGUI(QMainWindow):
title = "Автоматическая установка"
html_content = ("<h3>Автоматическая установка</h3>"
"<p>Скрипты из этого списка скачают, установят и настроят приложение за вас. Просто выберите программу и нажмите «Установить».</p>"
"<p>Для доступа к экспериментальным скриптам установки отметьте опцию <b>«Показать тестовые версии»</b> внизу списка.</p>"
"<br><h3>Совместимость с дистрибутивами Альт</h3>"
"<p>С полным списком совместимого ПО и сертификатами (не только для WineHelper) можно ознакомиться по следующим ссылкам:<br>"
"<a href='https://www.basealt.ru/fileadmin/user_upload/compatibility/P10-view2.html'>Для 10 платформы</a> | <a href='https://www.basealt.ru/fileadmin/user_upload/compatibility/P11-view2.html'>Для 11 платформы</a></p>")
"<p>Для доступа к экспериментальным скриптам установки отметьте опцию <b>«Показать тестовые версии»</b> внизу списка.</p>")
show_global = False
elif tab_name == "Ручная установка":
title = "Ручная установка"
@@ -2201,6 +2300,7 @@ class WineHelperGUI(QMainWindow):
self.install_tabs_data['auto'] = {
'buttons': buttons, 'layout': layout, 'search_edit': search_edit, 'scroll_area': scroll_area
}
self.install_tabs_data['auto']['test_buttons'] = []
# Добавляем чекбокс для тестовых версий
test_checkbox = QCheckBox("Показать тестовые версии")
@@ -2236,43 +2336,68 @@ class WineHelperGUI(QMainWindow):
if not data:
return
script_folders = ["autoinstall"]
if data['test_checkbox'].isChecked():
script_folders.append("testinstall")
is_checked = data['test_checkbox'].isChecked()
test_buttons = data.get('test_buttons', [])
# Перед удалением кнопок останавливаем все связанные с ними таймеры анимации
for btn in data['buttons']:
if btn in self.icon_animators:
anim_data = self.icon_animators.pop(btn)
if 'main_timer' in anim_data:
anim_data['main_timer'].stop()
if 'animation' in anim_data and anim_data['animation']:
anim_data['animation'].stop()
# Сбрасываем ссылку на активную кнопку, если она была удалена
if self.current_active_button in data['buttons']:
self.current_active_button = None
# Очищаем старые кнопки и layout
for btn in data['buttons']:
btn.parent().deleteLater()
data['buttons'].clear()
# Заполняем layout новыми кнопками
scripts = []
for folder in script_folders:
script_path = os.path.join(Var.DATA_PATH, folder)
# Если нужно показать тестовые версии и они еще не добавлены
if is_checked and not test_buttons:
test_script_folder = "testinstall"
script_path = os.path.join(Var.DATA_PATH, test_script_folder)
if os.path.isdir(script_path):
try:
folder_scripts = sorted(os.listdir(script_path))
self._populate_install_grid(data['layout'], folder_scripts, folder, data['buttons'])
scripts.extend(folder_scripts)
except OSError as e:
print(f"Не удалось прочитать директорию {script_path}: {e}")
# Запоминаем, какие кнопки являются тестовыми
new_test_buttons = []
self._populate_install_grid(data['layout'], folder_scripts, test_script_folder, new_test_buttons)
data['test_buttons'] = new_test_buttons
data['buttons'].extend(new_test_buttons)
self.autoinstall_scripts.extend(folder_scripts)
self.autoinstall_scripts = scripts
# Применяем текущий фильтр поиска к обновленному списку
self.filter_buttons('auto')
# Применяем фильтр и прокручиваем к первому новому элементу
self.filter_buttons('auto')
if new_test_buttons:
first_new_button = new_test_buttons[0]
frame = first_new_button.parent()
if isinstance(frame, QFrame):
# Даем время на отрисовку перед прокруткой
QTimer.singleShot(100, lambda: data['scroll_area'].ensureWidgetVisible(frame, 50, 50))
except OSError as e:
print(f"Не удалось прочитать директорию {test_script_folder}: {e}")
# Если нужно скрыть тестовые версии и они были добавлены
elif not is_checked and test_buttons:
# Если текущая активная кнопка находится среди удаляемых, сбрасываем ее
if self.current_active_button in test_buttons:
self._reset_info_panel_to_default("Автоматическая установка")
self.current_active_button = None
# Останавливаем анимацию и удаляем виджеты тестовых кнопок
for btn in test_buttons:
if btn in self.icon_animators:
anim_data = self.icon_animators.pop(btn)
if 'main_timer' in anim_data:
anim_data['main_timer'].stop()
if 'animation' in anim_data and anim_data['animation']:
anim_data['animation'].stop()
# Удаляем кнопку из основного списка
if btn in data['buttons']:
data['buttons'].remove(btn)
# Удаляем фрейм кнопки из layout
frame = btn.parent()
if frame:
frame.deleteLater()
# Очищаем список тестовых кнопок
data['test_buttons'].clear()
# Обновляем список скриптов
self.autoinstall_scripts = [s for s in self.autoinstall_scripts if not os.path.exists(os.path.join(Var.DATA_PATH, "testinstall", s))]
# В любом случае применяем фильтр, чтобы скрыть/показать кнопки в соответствии с поиском
if data['test_checkbox'].isChecked():
self.filter_buttons('auto')
def create_installed_tab(self):
"""Создает вкладку для отображения установленных программ в виде кнопок"""
@@ -3234,17 +3359,44 @@ class WineHelperGUI(QMainWindow):
help_subtabs = QTabWidget()
help_layout.addWidget(help_subtabs)
# Подвкладка "Руководство"
guide_tab = QWidget()
guide_layout = QVBoxLayout(guide_tab)
guide_text = QTextBrowser()
guide_text.setOpenExternalLinks(True)
guide_text.setHtml("""
<h2>Руководство пользователя</h2>
<p>Подробное и актуальное руководство по использованию WineHelper смотрите на <a href="https://www.altlinux.org/Winehelper">https://www.altlinux.org/Winehelper</a></p>
""")
guide_layout.addWidget(guide_text)
help_subtabs.addTab(guide_tab, "Руководство")
# Подвкладка "Общее"
general_tab = QWidget()
general_layout = QVBoxLayout(general_tab)
general_text = QTextBrowser()
general_text.setOpenExternalLinks(True)
try:
if not Var.GENERAL or not os.path.exists(Var.GENERAL):
raise FileNotFoundError
with open(Var.GENERAL, 'r', encoding='utf-8') as f:
general_content = f.read()
html_content = ""
url_re = re.compile(r'(https?://[^\s]+)')
for line in general_content.splitlines():
line = line.strip()
if not line:
html_content += "<br>"
continue
line = html.escape(line)
line = url_re.sub(r'<a href="\1">\1</a>', line)
if line.startswith('# '):
html_content += f'<h2>{line[2:]}</h2>'
elif line.startswith('Для '):
html_content += f'<p style="margin-left: 10px;">&bull; {line}</p>'
else:
html_content += f'<p>{line}</p>'
general_text.setHtml(html_content)
except (FileNotFoundError, TypeError):
general_text.setHtml(f'<h2>Ошибка</h2><p>Не удалось загрузить файл с общей информацией по пути:<br>{Var.GENERAL}</p>')
general_layout.addWidget(general_text)
help_subtabs.addTab(general_tab, "Общее")
# Подвкладка "Авторы"
authors_tab = QWidget()
@@ -4903,7 +5055,7 @@ def main():
window.server = server
window.show()
# Создаем иконку в системном трее после создания окна
window.create_tray_icon()
# window.create_tray_icon() # Временно отключено
return app.exec_()
return 1