forked from CastroFidel/winehelper
Compare commits
11 Commits
dfc6c1c836
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
151d0ffc48 | ||
|
|
ad91466475 | ||
|
|
5e4d94bb57 | ||
|
|
5b572ff540 | ||
|
|
c68bcc9abf | ||
|
|
1ad2c6cfa8 | ||
|
|
16a686dc37 | ||
|
|
c9d5619ab9 | ||
|
|
74311e9c04 | ||
|
|
eb9bef83e2 | ||
|
|
c7eddb8b53 |
7
GENERAL
Normal file
7
GENERAL
Normal 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
|
||||||
@@ -44,13 +44,13 @@ ADDONS_PATH_OPENSSH="${ADDONS_PATH}/OpenSSH"
|
|||||||
if try_download "$SCADOFFICE_ADDONS_URL" "${ADDONS_PACK}" ; then
|
if try_download "$SCADOFFICE_ADDONS_URL" "${ADDONS_PACK}" ; then
|
||||||
create_new_dir "${ADDONS_PATH}"
|
create_new_dir "${ADDONS_PATH}"
|
||||||
unpack "${ADDONS_PACK}" "${ADDONS_PATH}"
|
unpack "${ADDONS_PACK}" "${ADDONS_PATH}"
|
||||||
wine_run regedit "${ADDONS_PATH_REG}"/*.reg
|
wine_run "${ADDONS_PATH_REG}"/*.reg
|
||||||
|
|
||||||
# Установка ODBC
|
# Установка ODBC
|
||||||
rm -fR "$DRIVE_C/Program Files (x86)/Common Files/System"
|
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}/System" "$DRIVE_C/Program Files (x86)/Common Files/System"
|
||||||
cp -r "${ADDONS_PATH_MDAC}"/*.* "$DRIVE_C/windows/system32/"
|
cp -r "${ADDONS_PATH_MDAC}"/*.* "$DRIVE_C/windows/system32/"
|
||||||
wine_run regedit "${ADDONS_PATH_MDAC}"/*.reg
|
wine_run "${ADDONS_PATH_MDAC}"/*.reg
|
||||||
|
|
||||||
# Установка SSH
|
# Установка SSH
|
||||||
cp -r "${ADDONS_PATH_OPENSSH}" "$DRIVE_C/windows/system32/"
|
cp -r "${ADDONS_PATH_OPENSSH}" "$DRIVE_C/windows/system32/"
|
||||||
|
|||||||
27
winehelper
27
winehelper
@@ -7,7 +7,7 @@ if [[ $(id -u) -eq 0 ]] ; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
##### DEFAULT PATH #####
|
##### 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")"
|
SCRIPT_NAME="$(basename "$0")"
|
||||||
if [[ "$(realpath "$0")" == "/usr/bin/$SCRIPT_NAME" ]] ; then
|
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"
|
RUN_SCRIPT="/usr/bin/$SCRIPT_NAME"
|
||||||
DATA_PATH="/usr/share/$SCRIPT_NAME"
|
DATA_PATH="/usr/share/$SCRIPT_NAME"
|
||||||
WH_ICON_PATH="/usr/share/icons/hicolor/scalable/apps/winehelper.svg"
|
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"
|
CHANGELOG_FILE="/usr/share/doc/winehelper-$WH_VERSION/CHANGELOG"
|
||||||
LICENSE_FILE="/usr/share/doc/winehelper-$WH_VERSION/LICENSE"
|
LICENSE_FILE="/usr/share/doc/winehelper-$WH_VERSION/LICENSE"
|
||||||
AGREEMENT="/usr/share/doc/winehelper-$WH_VERSION/LICENSE_AGREEMENT"
|
AGREEMENT="/usr/share/doc/winehelper-$WH_VERSION/LICENSE_AGREEMENT"
|
||||||
THIRD_PARTY_FILE="/usr/share/doc/winehelper-$WH_VERSION/THIRD-PARTY"
|
THIRD_PARTY_FILE="/usr/share/doc/winehelper-$WH_VERSION/THIRD-PARTY"
|
||||||
|
GENERAL="/usr/share/doc/winehelper-$WH_VERSION/GENERAL"
|
||||||
else
|
else
|
||||||
# переменные для тестового запуска WineHelper из репозитория
|
# переменные для тестового запуска WineHelper из репозитория
|
||||||
USER_WORK_PATH="$HOME/test-$SCRIPT_NAME"
|
USER_WORK_PATH="$HOME/test-$SCRIPT_NAME"
|
||||||
@@ -33,6 +34,7 @@ else
|
|||||||
LICENSE_FILE="$DATA_PATH/LICENSE"
|
LICENSE_FILE="$DATA_PATH/LICENSE"
|
||||||
AGREEMENT="$DATA_PATH/LICENSE_AGREEMENT"
|
AGREEMENT="$DATA_PATH/LICENSE_AGREEMENT"
|
||||||
THIRD_PARTY_FILE="$DATA_PATH/THIRD-PARTY"
|
THIRD_PARTY_FILE="$DATA_PATH/THIRD-PARTY"
|
||||||
|
GENERAL="$DATA_PATH/GENERAL"
|
||||||
WH_DEVEL="1"
|
WH_DEVEL="1"
|
||||||
|
|
||||||
# минимальная проверка синтаксиса скриптов
|
# минимальная проверка синтаксиса скриптов
|
||||||
@@ -52,21 +54,21 @@ fi
|
|||||||
|
|
||||||
##### MESSAGES FUNCTIONS #####
|
##### MESSAGES FUNCTIONS #####
|
||||||
if [[ $WH_USE_GUI != "1" ]] ; then
|
if [[ $WH_USE_GUI != "1" ]] ; then
|
||||||
print_error () { printf "\E[31m%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_warning () { printf "\E[33m%s Предупреждение: $* %s\e[0m\n" ;}
|
||||||
print_info () { printf "\E[36m%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_ok () { printf "\E[35m%s Успех: $* %s\e[0m\n" ;}
|
||||||
else
|
else
|
||||||
print_error () { echo -e "Ошибка: $@" ;}
|
print_error () { echo -e "Ошибка: $*" ;}
|
||||||
print_warning () { echo -e "Предупреждение: $@" ;}
|
print_warning () { echo -e "Предупреждение: $*" ;}
|
||||||
print_info () { echo -e "Информация: \"$@\"" ;}
|
print_info () { echo -e "Информация: \"$*\"" ;}
|
||||||
print_ok () { echo -e "Успех: $@" ;}
|
print_ok () { echo -e "Успех: $*" ;}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_var () { for vp in $@ ; do echo "${vp}=${!vp}" ; done ;}
|
print_var () { for vp in $@ ; do echo "${vp}=${!vp}" ; done ;}
|
||||||
|
|
||||||
fatal () {
|
fatal () {
|
||||||
print_error "$@"
|
print_error "$@ Аварийное завершение работы WineHelper!"
|
||||||
[[ -n "$WINESERVER" ]] && "$WINESERVER" -w
|
[[ -n "$WINESERVER" ]] && "$WINESERVER" -w
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
@@ -326,6 +328,7 @@ unpack () {
|
|||||||
try_get_page () {
|
try_get_page () {
|
||||||
local url_page="$1"
|
local url_page="$1"
|
||||||
export OUT_PAGE_TMP="${WH_TMP_DIR}/url_page.tmp"
|
export OUT_PAGE_TMP="${WH_TMP_DIR}/url_page.tmp"
|
||||||
|
try_remove_file "$OUT_PAGE_TMP"
|
||||||
print_info "Чтение страницы: $url_page"
|
print_info "Чтение страницы: $url_page"
|
||||||
if ! curl -o "$OUT_PAGE_TMP" -A "Mozilla/5.0 (compatible; Konqueror/2.1.1; X11)" "$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"
|
|| grep -q "Forbidden" "$OUT_PAGE_TMP"
|
||||||
@@ -342,7 +345,6 @@ read_page () {
|
|||||||
&& [[ -f "$OUT_PAGE_TMP" ]]
|
&& [[ -f "$OUT_PAGE_TMP" ]]
|
||||||
then
|
then
|
||||||
cat "$OUT_PAGE_TMP"
|
cat "$OUT_PAGE_TMP"
|
||||||
try_remove_file "$OUT_PAGE_TMP"
|
|
||||||
unset OUT_PAGE_TMP
|
unset OUT_PAGE_TMP
|
||||||
else
|
else
|
||||||
echo "Используй try_get_page перед read_page"
|
echo "Используй try_get_page перед read_page"
|
||||||
@@ -1539,6 +1541,7 @@ run_autoinstall () {
|
|||||||
else print_license_agreement
|
else print_license_agreement
|
||||||
fi
|
fi
|
||||||
source "$INSTALL_SCRIPT" "$@"
|
source "$INSTALL_SCRIPT" "$@"
|
||||||
|
[[ -n $OUT_PAGE_TMP ]] && try_remove_file "$OUT_PAGE_TMP"
|
||||||
print_info "Завершена установка $INSTALL_SCRIPT_NAME"
|
print_info "Завершена установка $INSTALL_SCRIPT_NAME"
|
||||||
else
|
else
|
||||||
fatal "Скрипт автоматической установки для $INSTALL_SCRIPT_NAME не найден!"
|
fatal "Скрипт автоматической установки для $INSTALL_SCRIPT_NAME не найден!"
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ 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, QInputDialog, QDialogButtonBox, QSystemTrayIcon, QMenu)
|
QListWidget, QListWidgetItem, QGridLayout, QFrame, QDialog, QTextBrowser, QInputDialog, QDialogButtonBox, QSystemTrayIcon, QMenu)
|
||||||
from PyQt5.QtCore import Qt, QProcess, QSize, QTimer, QProcessEnvironment, QPropertyAnimation, QEasingCurve, pyqtSignal
|
from PyQt5.QtCore import Qt, QProcess, QSize, QTimer, QProcessEnvironment, QPropertyAnimation, QEasingCurve, pyqtSignal, QRect
|
||||||
from PyQt5.QtGui import QIcon, QFont, QTextCursor, QPixmap, QPainter, QCursor, QTextCharFormat
|
from PyQt5.QtGui import QIcon, QFont, QTextCursor, QPixmap, QPainter, QCursor, QTextCharFormat, QColor, QPalette
|
||||||
from PyQt5.QtNetwork import QLocalServer, QLocalSocket
|
from PyQt5.QtNetwork import QLocalServer, QLocalSocket
|
||||||
|
|
||||||
|
|
||||||
@@ -26,9 +26,11 @@ class Var:
|
|||||||
DATA_PATH = os.environ.get("DATA_PATH")
|
DATA_PATH = os.environ.get("DATA_PATH")
|
||||||
CHANGELOG_FILE = os.environ.get("CHANGELOG_FILE")
|
CHANGELOG_FILE = os.environ.get("CHANGELOG_FILE")
|
||||||
WH_ICON_PATH = os.environ.get("WH_ICON_PATH")
|
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_FILE = os.environ.get("LICENSE_FILE")
|
||||||
LICENSE_AGREEMENT_FILE = os.environ.get("AGREEMENT")
|
LICENSE_AGREEMENT_FILE = os.environ.get("AGREEMENT")
|
||||||
THIRD_PARTY_FILE = os.environ.get("THIRD_PARTY_FILE")
|
THIRD_PARTY_FILE = os.environ.get("THIRD_PARTY_FILE")
|
||||||
|
GENERAL = os.environ.get("GENERAL")
|
||||||
|
|
||||||
class DependencyManager:
|
class DependencyManager:
|
||||||
"""Класс для управления проверкой и установкой системных зависимостей."""
|
"""Класс для управления проверкой и установкой системных зависимостей."""
|
||||||
@@ -1737,6 +1739,18 @@ class WineHelperGUI(QMainWindow):
|
|||||||
self.raise_()
|
self.raise_()
|
||||||
self.activateWindow()
|
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):
|
def create_tray_icon(self):
|
||||||
"""Создает и настраивает иконку в системном трее."""
|
"""Создает и настраивает иконку в системном трее."""
|
||||||
if not QSystemTrayIcon.isSystemTrayAvailable():
|
if not QSystemTrayIcon.isSystemTrayAvailable():
|
||||||
@@ -1745,11 +1759,23 @@ class WineHelperGUI(QMainWindow):
|
|||||||
|
|
||||||
self.tray_icon = QSystemTrayIcon(self)
|
self.tray_icon = QSystemTrayIcon(self)
|
||||||
|
|
||||||
icon_path = Var.WH_ICON_PATH
|
# --- Определение цвета иконки в зависимости от темы ---
|
||||||
if icon_path and os.path.exists(icon_path):
|
if Var.WH_ICON_TRAY and os.path.exists(Var.WH_ICON_TRAY):
|
||||||
pixmap = QPixmap(icon_path)
|
# Получаем цвет текста окна из палитры приложения.
|
||||||
if not pixmap.isNull():
|
# Это хороший индикатор для определения контрастного цвета.
|
||||||
self.tray_icon.setIcon(QIcon(pixmap))
|
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)
|
self.tray_menu = QMenu(self)
|
||||||
@@ -1792,10 +1818,7 @@ class WineHelperGUI(QMainWindow):
|
|||||||
title = "Автоматическая установка"
|
title = "Автоматическая установка"
|
||||||
html_content = ("<h3>Автоматическая установка</h3>"
|
html_content = ("<h3>Автоматическая установка</h3>"
|
||||||
"<p>Скрипты из этого списка скачают, установят и настроят приложение за вас. Просто выберите программу и нажмите «Установить».</p>"
|
"<p>Скрипты из этого списка скачают, установят и настроят приложение за вас. Просто выберите программу и нажмите «Установить».</p>"
|
||||||
"<p>Для доступа к экспериментальным скриптам установки отметьте опцию <b>«Показать тестовые версии»</b> внизу списка.</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>")
|
|
||||||
show_global = False
|
show_global = False
|
||||||
elif tab_name == "Ручная установка":
|
elif tab_name == "Ручная установка":
|
||||||
title = "Ручная установка"
|
title = "Ручная установка"
|
||||||
@@ -2201,6 +2224,7 @@ class WineHelperGUI(QMainWindow):
|
|||||||
self.install_tabs_data['auto'] = {
|
self.install_tabs_data['auto'] = {
|
||||||
'buttons': buttons, 'layout': layout, 'search_edit': search_edit, 'scroll_area': scroll_area
|
'buttons': buttons, 'layout': layout, 'search_edit': search_edit, 'scroll_area': scroll_area
|
||||||
}
|
}
|
||||||
|
self.install_tabs_data['auto']['test_buttons'] = []
|
||||||
|
|
||||||
# Добавляем чекбокс для тестовых версий
|
# Добавляем чекбокс для тестовых версий
|
||||||
test_checkbox = QCheckBox("Показать тестовые версии")
|
test_checkbox = QCheckBox("Показать тестовые версии")
|
||||||
@@ -2236,43 +2260,63 @@ class WineHelperGUI(QMainWindow):
|
|||||||
if not data:
|
if not data:
|
||||||
return
|
return
|
||||||
|
|
||||||
script_folders = ["autoinstall"]
|
is_checked = data['test_checkbox'].isChecked()
|
||||||
if data['test_checkbox'].isChecked():
|
test_buttons = data.get('test_buttons', [])
|
||||||
script_folders.append("testinstall")
|
|
||||||
|
|
||||||
# Перед удалением кнопок останавливаем все связанные с ними таймеры анимации
|
# Если нужно показать тестовые версии и они еще не добавлены
|
||||||
for btn in data['buttons']:
|
if is_checked and not test_buttons:
|
||||||
if btn in self.icon_animators:
|
test_script_folder = "testinstall"
|
||||||
anim_data = self.icon_animators.pop(btn)
|
script_path = os.path.join(Var.DATA_PATH, test_script_folder)
|
||||||
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 os.path.isdir(script_path):
|
if os.path.isdir(script_path):
|
||||||
try:
|
try:
|
||||||
folder_scripts = sorted(os.listdir(script_path))
|
folder_scripts = sorted(os.listdir(script_path))
|
||||||
self._populate_install_grid(data['layout'], folder_scripts, folder, data['buttons'])
|
# Запоминаем, какие кнопки являются тестовыми
|
||||||
scripts.extend(folder_scripts)
|
new_test_buttons = []
|
||||||
except OSError as e:
|
self._populate_install_grid(data['layout'], folder_scripts, test_script_folder, new_test_buttons)
|
||||||
print(f"Не удалось прочитать директорию {script_path}: {e}")
|
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:
|
||||||
|
# Останавливаем анимацию и удаляем виджеты тестовых кнопок
|
||||||
|
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):
|
def create_installed_tab(self):
|
||||||
"""Создает вкладку для отображения установленных программ в виде кнопок"""
|
"""Создает вкладку для отображения установленных программ в виде кнопок"""
|
||||||
@@ -3234,17 +3278,44 @@ class WineHelperGUI(QMainWindow):
|
|||||||
help_subtabs = QTabWidget()
|
help_subtabs = QTabWidget()
|
||||||
help_layout.addWidget(help_subtabs)
|
help_layout.addWidget(help_subtabs)
|
||||||
|
|
||||||
# Подвкладка "Руководство"
|
# Подвкладка "Общее"
|
||||||
guide_tab = QWidget()
|
general_tab = QWidget()
|
||||||
guide_layout = QVBoxLayout(guide_tab)
|
general_layout = QVBoxLayout(general_tab)
|
||||||
guide_text = QTextBrowser()
|
general_text = QTextBrowser()
|
||||||
guide_text.setOpenExternalLinks(True)
|
general_text.setOpenExternalLinks(True)
|
||||||
guide_text.setHtml("""
|
|
||||||
<h2>Руководство пользователя</h2>
|
try:
|
||||||
<p>Подробное и актуальное руководство по использованию WineHelper смотрите на <a href="https://www.altlinux.org/Winehelper">https://www.altlinux.org/Winehelper</a></p>
|
if not Var.GENERAL or not os.path.exists(Var.GENERAL):
|
||||||
""")
|
raise FileNotFoundError
|
||||||
guide_layout.addWidget(guide_text)
|
|
||||||
help_subtabs.addTab(guide_tab, "Руководство")
|
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;">• {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()
|
authors_tab = QWidget()
|
||||||
@@ -4903,7 +4974,7 @@ def main():
|
|||||||
window.server = server
|
window.server = server
|
||||||
window.show()
|
window.show()
|
||||||
# Создаем иконку в системном трее после создания окна
|
# Создаем иконку в системном трее после создания окна
|
||||||
window.create_tray_icon()
|
# window.create_tray_icon() # Временно отключено
|
||||||
return app.exec_()
|
return app.exec_()
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
Reference in New Issue
Block a user