diff --git a/CHANGELOG.md b/CHANGELOG.md index 5eed002b..cb3b5d32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [0.9.22] +### Improvements +- UI + - settings panel: + - always displaying all supported packaging technologies + - displaying a tooltip with the missing dependencies for a supported packaging technology +

+ +

+ ### Fixes - Arch - **wget** as a hard requirement for Arch package management diff --git a/bauh/api/abstract/controller.py b/bauh/api/abstract/controller.py index 7c009539..1f805b11 100644 --- a/bauh/api/abstract/controller.py +++ b/bauh/api/abstract/controller.py @@ -4,7 +4,7 @@ import shutil from abc import ABC, abstractmethod from enum import Enum from pathlib import Path -from typing import List, Set, Type, Tuple, Optional +from typing import List, Set, Type, Tuple, Optional, Generator import yaml @@ -243,9 +243,9 @@ class SoftwareManager(ABC): pass @abstractmethod - def can_work(self) -> bool: + def can_work(self) -> Tuple[bool, Optional[str]]: """ - :return: if the instance can work based on what is installed in the user's machine. + :return: if the instance can work based on what is installed in the user's machine. If not, an optional string as a reason. """ def cache_to_disk(self, pkg: SoftwarePackage, icon_bytes: Optional[bytes], only_icon: bool): diff --git a/bauh/api/abstract/download.py b/bauh/api/abstract/download.py index 5b54e589..8c4eb970 100644 --- a/bauh/api/abstract/download.py +++ b/bauh/api/abstract/download.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import Iterable, List, Optional +from typing import Iterable, List, Optional, Tuple from bauh.api.abstract.handler import ProcessWatcher @@ -41,3 +41,7 @@ class FileDownloader(ABC): @abstractmethod def list_available_multithreaded_clients(self) -> List[str]: pass + + @abstractmethod + def get_supported_clients(self) -> tuple: + pass diff --git a/bauh/api/abstract/view.py b/bauh/api/abstract/view.py index 5492776c..35102601 100644 --- a/bauh/api/abstract/view.py +++ b/bauh/api/abstract/view.py @@ -1,6 +1,6 @@ from abc import ABC from enum import Enum -from typing import List, Set, Optional +from typing import List, Set, Optional, Dict class MessageType(Enum): @@ -46,13 +46,14 @@ class InputOption: def __init__(self, label: str, value: object, tooltip: Optional[str] = None, icon_path: Optional[str] = None, read_only: bool = False, id_: Optional[str] = None, - invalid: bool = False): + invalid: bool = False, extra_properties: Optional[Dict[str, str]] = None): """ :param label: the string that will be shown to the user :param value: the option value (not shown) :param tooltip: an optional tooltip :param icon_path: an optional icon path :param invalid: if this option is considered invalid + :param extra_properties: extra properties """ if not label: raise Exception("'label' must be a not blank string") @@ -64,6 +65,7 @@ class InputOption: self.icon_path = icon_path self.read_only = read_only self.invalid = invalid + self.extra_properties = extra_properties def __hash__(self): return hash(self.label) + hash(self.value) diff --git a/bauh/gems/appimage/controller.py b/bauh/gems/appimage/controller.py index 5cc6d44f..3dd64daf 100644 --- a/bauh/gems/appimage/controller.py +++ b/bauh/gems/appimage/controller.py @@ -680,8 +680,15 @@ class AppImageManager(SoftwareManager): def _is_sqlite3_available(self) -> bool: return bool(shutil.which('sqlite3')) - def can_work(self) -> bool: - return self._is_sqlite3_available() and self.file_downloader.can_work() + def can_work(self) -> Tuple[bool, Optional[str]]: + if not self._is_sqlite3_available(): + return False, self.i18n['missing_dep'].format(dep=bold('sqlite3')) + + if not self.file_downloader.can_work(): + download_clients = ', '.join(self.file_downloader.get_supported_clients()) + return False, self.i18n['appimage.missing_downloader'].format(clients=download_clients) + + return True, None def requires_root(self, action: SoftwareAction, pkg: AppImage) -> bool: return False diff --git a/bauh/gems/appimage/resources/locale/ca b/bauh/gems/appimage/resources/locale/ca index 6e001ac4..073ad6b1 100644 --- a/bauh/gems/appimage/resources/locale/ca +++ b/bauh/gems/appimage/resources/locale/ca @@ -33,6 +33,7 @@ appimage.install.desktop_entry=S’està creant una drecera del menú appimage.install.extract=S’està extraient el contingut de {} appimage.install.imported.rename_error=It was not possible to move the file {} to {} appimage.install.permission=S’està concedint el permís d’execució a {} +appimage.missing_downloader=No download client installed ({clients}) appimage.update_database.deleting_old=Removing old files appimage.update_database.downloading=Downloading database files appimage.update_database.uncompressing=Uncompressing files diff --git a/bauh/gems/appimage/resources/locale/de b/bauh/gems/appimage/resources/locale/de index 809b4e57..425733b3 100644 --- a/bauh/gems/appimage/resources/locale/de +++ b/bauh/gems/appimage/resources/locale/de @@ -33,6 +33,7 @@ appimage.install.desktop_entry=Menü-Shortcut erstellen appimage.install.extract=Entpacke Inhalt von {} appimage.install.imported.rename_error=It was not possible to move the file {} to {} appimage.install.permission=Ausführberechtigungen für {} +appimage.missing_downloader=No download client installed ({clients}) appimage.update_database.deleting_old=Removing old files appimage.update_database.downloading=Downloading database files appimage.update_database.uncompressing=Uncompressing files diff --git a/bauh/gems/appimage/resources/locale/en b/bauh/gems/appimage/resources/locale/en index d30d5989..5189c039 100644 --- a/bauh/gems/appimage/resources/locale/en +++ b/bauh/gems/appimage/resources/locale/en @@ -33,6 +33,7 @@ appimage.install.desktop_entry=Generating a menu shortcut appimage.install.extract=Extracting the content from {} appimage.install.imported.rename_error=It was not possible to move the file {} to {} appimage.install.permission=Giving execution permission to {} +appimage.missing_downloader=No download client installed ({clients}) appimage.update_database.deleting_old=Removing old files appimage.update_database.downloading=Downloading database files appimage.update_database.uncompressing=Uncompressing files diff --git a/bauh/gems/appimage/resources/locale/es b/bauh/gems/appimage/resources/locale/es index 344d3cae..2ae6a1bf 100644 --- a/bauh/gems/appimage/resources/locale/es +++ b/bauh/gems/appimage/resources/locale/es @@ -33,6 +33,7 @@ appimage.install.desktop_entry=Creando un atajo en el menú appimage.install.extract=Extrayendo el contenido de {} appimage.install.imported.rename_error=No fue posible mover el archivo {} a {} appimage.install.permission=Concediendo permiso de ejecución a {} +appimage.missing_downloader=No hay ningún cliente de descarga instalado ({clients}) appimage.update_database.deleting_old=Eliminando archivos antiguos appimage.update_database.downloading=Descargando archivos de la base de datos appimage.update_database.uncompressing=Descomprindo archivos diff --git a/bauh/gems/appimage/resources/locale/fr b/bauh/gems/appimage/resources/locale/fr index 6c6699cf..9b0f1a9b 100644 --- a/bauh/gems/appimage/resources/locale/fr +++ b/bauh/gems/appimage/resources/locale/fr @@ -32,6 +32,7 @@ appimage.install.download.error=Échec du téléchargement du fichier {}. Le ser appimage.install.extract=Extractiion du contenu de {} appimage.install.imported.rename_error=Impossible de déplacer {} vers {} appimage.install.permission={} est maintenant exécutable +appimage.missing_downloader=No download client installed ({clients}) appimage.update_database.deleting_old=Removing old files appimage.update_database.downloading=Downloading database files appimage.update_database.uncompressing=Uncompressing files diff --git a/bauh/gems/appimage/resources/locale/it b/bauh/gems/appimage/resources/locale/it index 9b9330ce..52f6fefd 100644 --- a/bauh/gems/appimage/resources/locale/it +++ b/bauh/gems/appimage/resources/locale/it @@ -33,6 +33,7 @@ appimage.install.download.error=Non è stato possibile scaricare il file {}. Il appimage.install.extract=Estrarre il contenuto da {} appimage.install.imported.rename_error=It was not possible to move the file {} to {} appimage.install.permission=Gdare il permesso di esecuzione a {} +appimage.missing_downloader=No download client installed ({clients}) appimage.update_database.deleting_old=Removing old files appimage.update_database.downloading=Downloading database files appimage.update_database.uncompressing=Uncompressing files diff --git a/bauh/gems/appimage/resources/locale/pt b/bauh/gems/appimage/resources/locale/pt index 51e1dd98..5b290f73 100644 --- a/bauh/gems/appimage/resources/locale/pt +++ b/bauh/gems/appimage/resources/locale/pt @@ -33,6 +33,7 @@ appimage.install.desktop_entry=Criando um atalho no menu appimage.install.extract=Extraindo o conteúdo de {} appimage.install.imported.rename_error=Não foi possível mover o arquivo {} para {} appimage.install.permission=Concedendo permissão de execução para {} +appimage.missing_downloader=Nenhum cliente de para download está instalado ({clients}) appimage.update_database.deleting_old=Removendo arquicos antigos appimage.update_database.downloading=Baixando arquivos do banco de dados appimage.update_database.uncompressing=Descomprimindo arquivos diff --git a/bauh/gems/appimage/resources/locale/ru b/bauh/gems/appimage/resources/locale/ru index f5d2ff1a..0e329cf2 100644 --- a/bauh/gems/appimage/resources/locale/ru +++ b/bauh/gems/appimage/resources/locale/ru @@ -33,6 +33,7 @@ appimage.install.desktop_entry=Создать ярлык в меню appimage.install.extract=Извлечь содержимое из {} appimage.install.imported.rename_error=Не удалось переместить файл {} в {} appimage.install.permission=Установить права на выполнение для {} +appimage.missing_downloader=No download client installed ({clients}) appimage.update_database.deleting_old=Removing old files appimage.update_database.downloading=Downloading database files appimage.update_database.uncompressing=Uncompressing files diff --git a/bauh/gems/appimage/resources/locale/tr b/bauh/gems/appimage/resources/locale/tr index 2c0f79e6..9a5f3d6d 100644 --- a/bauh/gems/appimage/resources/locale/tr +++ b/bauh/gems/appimage/resources/locale/tr @@ -33,6 +33,7 @@ appimage.install.desktop_entry=Bir menü kısayolu oluşturuluyor appimage.install.extract={} 'den içerik ayıklanıyor appimage.install.imported.rename_error={} dosyasını {} klasörüne taşımak mümkün değildi appimage.install.permission={} için yürütme izni veriliyor +appimage.missing_downloader=No download client installed ({clients}) appimage.update_database.deleting_old=Removing old files appimage.update_database.downloading=Downloading database files appimage.update_database.uncompressing=Uncompressing files diff --git a/bauh/gems/arch/controller.py b/bauh/gems/arch/controller.py index 9e01871e..4cbcd2b3 100644 --- a/bauh/gems/arch/controller.py +++ b/bauh/gems/arch/controller.py @@ -11,7 +11,7 @@ from datetime import datetime from math import floor from pathlib import Path from threading import Thread -from typing import List, Set, Type, Tuple, Dict, Iterable, Optional, Collection +from typing import List, Set, Type, Tuple, Dict, Iterable, Optional, Collection, Generator import requests from dateutil.parser import parse as parse_date @@ -2649,8 +2649,14 @@ class ArchManager(SoftwareManager): def set_enabled(self, enabled: bool): self.enabled = enabled - def can_work(self) -> bool: - return self.arch_distro and pacman.is_available() + def can_work(self) -> Tuple[bool, Optional[str]]: + if not self.arch_distro: + return False, self.i18n['arch.can_work.not_arch_distro'] + + if not pacman.is_available(): + return False, self.i18n['missing_dep'].format(dep=bold('pacman')) + + return True, None def cache_to_disk(self, pkg: ArchPackage, icon_bytes: bytes, only_icon: bool): pass diff --git a/bauh/gems/arch/resources/locale/ca b/bauh/gems/arch/resources/locale/ca index 3075d0bb..4b4f9337 100644 --- a/bauh/gems/arch/resources/locale/ca +++ b/bauh/gems/arch/resources/locale/ca @@ -37,6 +37,7 @@ arch.aur.sync.several_names.popup.body=The definition file (PKGBUILD) of {} conf arch.aur.sync.several_names.popup.bt_only_chosen=Build only {} arch.aur.sync.several_names.popup.bt_selected=Build selected too arch.building.package=S’està compilant el paquet {} +arch.can_work.not_arch_distro=Only available for ArchLinux based distributions arch.checking.conflicts=S’està comprovant si hi ha conflictes amb {} arch.checking.deps=S’estan comprovant les dependències de {} arch.checking.missing_deps=Verificació de les dependències que falten de {} diff --git a/bauh/gems/arch/resources/locale/de b/bauh/gems/arch/resources/locale/de index 169854ed..4f92a835 100644 --- a/bauh/gems/arch/resources/locale/de +++ b/bauh/gems/arch/resources/locale/de @@ -37,6 +37,7 @@ arch.aur.sync.several_names.popup.body=The definition file (PKGBUILD) of {} conf arch.aur.sync.several_names.popup.bt_only_chosen=Build only {} arch.aur.sync.several_names.popup.bt_selected=Build selected too arch.building.package=Paket {} erstellen +arch.can_work.not_arch_distro=Only available for ArchLinux based distributions arch.checking.conflicts=Konflikte mit {} überprüfen arch.checking.deps={} Abhängigkeiten überprüfen arch.checking.missing_deps=Überprüfen der fehlenden Abhängigkeiten von {} diff --git a/bauh/gems/arch/resources/locale/en b/bauh/gems/arch/resources/locale/en index 42d40bbd..26935450 100644 --- a/bauh/gems/arch/resources/locale/en +++ b/bauh/gems/arch/resources/locale/en @@ -37,6 +37,7 @@ arch.aur.sync.several_names.popup.body=The definition file (PKGBUILD) of {} conf arch.aur.sync.several_names.popup.bt_only_chosen=Build only {} arch.aur.sync.several_names.popup.bt_selected=Build selected too arch.building.package=Building package {} +arch.can_work.not_arch_distro=Only available for ArchLinux based distributions arch.checking.conflicts=Checking any conflicts with {} arch.checking.deps=Checking {} dependencies arch.checking.missing_deps=Verifying missing dependencies of {} diff --git a/bauh/gems/arch/resources/locale/es b/bauh/gems/arch/resources/locale/es index d46548bb..674343ab 100644 --- a/bauh/gems/arch/resources/locale/es +++ b/bauh/gems/arch/resources/locale/es @@ -37,6 +37,7 @@ arch.aur.sync.several_names.popup.body=El archivo de definición (PKGBUILD) de { arch.aur.sync.several_names.popup.bt_only_chosen=Compilar sólo {} arch.aur.sync.several_names.popup.bt_selected=Compilar seleccionados también arch.building.package=Construyendo el paquete {} +arch.can_work.not_arch_distro=Solo disponible para distribuciones basadas en ArchLinux arch.checking.conflicts=Verificando se hay conflictos con {} arch.checking.deps=Verificando las dependencias de {} arch.checking.missing_deps=Verificando las dependencias faltantes de {} diff --git a/bauh/gems/arch/resources/locale/fr b/bauh/gems/arch/resources/locale/fr index a9c76178..23db1bee 100644 --- a/bauh/gems/arch/resources/locale/fr +++ b/bauh/gems/arch/resources/locale/fr @@ -37,6 +37,7 @@ arch.aur.sync.several_names.popup.body=Le fichier de définition (PKGBUILD) de { arch.aur.sync.several_names.popup.bt_only_chosen=Compiler seulement {} arch.aur.sync.several_names.popup.bt_selected=Compilation sélectionnée aussi arch.building.package=Compilation de {} +arch.can_work.not_arch_distro=Only available for ArchLinux based distributions arch.checking.conflicts=Vérification de conflits aved {} arch.checking.deps=Vérification des dépendances de {} arch.checking.missing_deps=Vérification des dépendances manquantes de {} diff --git a/bauh/gems/arch/resources/locale/it b/bauh/gems/arch/resources/locale/it index 0a86345f..8af43cc5 100644 --- a/bauh/gems/arch/resources/locale/it +++ b/bauh/gems/arch/resources/locale/it @@ -37,6 +37,7 @@ arch.aur.sync.several_names.popup.body=The definition file (PKGBUILD) of {} conf arch.aur.sync.several_names.popup.bt_only_chosen=Build only {} arch.aur.sync.several_names.popup.bt_selected=Build selected too arch.building.package=Pacchetto costruito {} +arch.can_work.not_arch_distro=Only available for ArchLinux based distributions arch.checking.conflicts=Verifica di eventuali conflitti con {} arch.checking.deps=Verifica di {} dipendenze arch.checking.missing_deps=Verifica delle dipendenze mancanti di {} diff --git a/bauh/gems/arch/resources/locale/pt b/bauh/gems/arch/resources/locale/pt index 7f1c2783..4037df26 100644 --- a/bauh/gems/arch/resources/locale/pt +++ b/bauh/gems/arch/resources/locale/pt @@ -37,6 +37,7 @@ arch.aur.sync.several_names.popup.body=O arquivo de definição (PKGBUILD) de {} arch.aur.sync.several_names.popup.bt_only_chosen=Construir somente {} arch.aur.sync.several_names.popup.bt_selected=Construir selecionados também arch.building.package=Construindo o pacote {} +arch.can_work.not_arch_distro=Somente disponível para distribuições baseadas em ArchLinux arch.checking.conflicts=Verificando se há conflitos com {} arch.checking.deps=Verificando as dependências de {} arch.checking.missing_deps=Verificando dependências ausentes de {} diff --git a/bauh/gems/arch/resources/locale/ru b/bauh/gems/arch/resources/locale/ru index f91ce42e..36b9f4d2 100644 --- a/bauh/gems/arch/resources/locale/ru +++ b/bauh/gems/arch/resources/locale/ru @@ -37,6 +37,7 @@ arch.aur.sync.several_names.popup.body=The definition file (PKGBUILD) of {} conf arch.aur.sync.several_names.popup.bt_only_chosen=Build only {} arch.aur.sync.several_names.popup.bt_selected=Build selected too arch.building.package=Сборка пакета {} +arch.can_work.not_arch_distro=Only available for ArchLinux based distributions arch.checking.conflicts=Проверка конфликтов с {} arch.checking.deps=Проверка зависимостей {} arch.checking.missing_deps=Проверка отсутствующих зависимостей {} diff --git a/bauh/gems/arch/resources/locale/tr b/bauh/gems/arch/resources/locale/tr index 720dc739..b90b42de 100644 --- a/bauh/gems/arch/resources/locale/tr +++ b/bauh/gems/arch/resources/locale/tr @@ -37,6 +37,7 @@ arch.aur.sync.several_names.popup.body=The definition file (PKGBUILD) of {} conf arch.aur.sync.several_names.popup.bt_only_chosen=Build only {} arch.aur.sync.several_names.popup.bt_selected=Build selected too arch.building.package=Paket inşa ediliyor {} +arch.can_work.not_arch_distro=Only available for ArchLinux based distributions arch.checking.conflicts={} ile çakışmalar kontrol ediliyor arch.checking.deps={} bağımlılıkları kontrol ediliyor arch.checking.missing_deps={} eksik bağımlılıkları kontrol ediliyor diff --git a/bauh/gems/flatpak/controller.py b/bauh/gems/flatpak/controller.py index 71b12a6f..8050eea2 100644 --- a/bauh/gems/flatpak/controller.py +++ b/bauh/gems/flatpak/controller.py @@ -484,8 +484,8 @@ class FlatpakManager(SoftwareManager): def set_enabled(self, enabled: bool): self.enabled = enabled - def can_work(self) -> bool: - return flatpak.is_installed() + def can_work(self) -> Tuple[bool, Optional[str]]: + return (True, None) if flatpak.is_installed() else (False, self.i18n['missing_dep'].format(dep=bold('flatpak'))) def requires_root(self, action: SoftwareAction, pkg: FlatpakApplication) -> bool: return action == SoftwareAction.DOWNGRADE and pkg.installation == 'system' diff --git a/bauh/gems/snap/controller.py b/bauh/gems/snap/controller.py index fc8c7b67..6674d49d 100644 --- a/bauh/gems/snap/controller.py +++ b/bauh/gems/snap/controller.py @@ -253,8 +253,8 @@ class SnapManager(SoftwareManager): def set_enabled(self, enabled: bool): self.enabled = enabled - def can_work(self) -> bool: - return snap.is_installed() + def can_work(self) -> Tuple[bool, Optional[str]]: + return (True, None) if snap.is_installed() else (False, self.i18n['missing_dep'].format(dep=bold('snap'))) def requires_root(self, action: SoftwareAction, pkg: SnapApplication) -> bool: return action not in (SoftwareAction.PREPARE, SoftwareAction.SEARCH) diff --git a/bauh/gems/web/controller.py b/bauh/gems/web/controller.py index 8d67ec72..8971a1f6 100644 --- a/bauh/gems/web/controller.py +++ b/bauh/gems/web/controller.py @@ -795,17 +795,23 @@ class WebApplicationManager(SoftwareManager): def set_enabled(self, enabled: bool): self.enabled = enabled - def can_work(self) -> bool: - if BS4_AVAILABLE and LXML_AVAILABLE: - config = self.configman.get_config() - use_system_env = config['environment']['system'] + def can_work(self) -> Tuple[bool, Optional[str]]: + if not BS4_AVAILABLE: + return False, self.i18n['missing_dep'].format(dep=bold('python3-beautifulsoup4')) - if not use_system_env: - return True + if not LXML_AVAILABLE: + return False, self.i18n['missing_dep'].format(dep=bold('python3-lxml')) - return nativefier.is_available() + config = self.configman.get_config() + use_system_env = config['environment']['system'] - return False + if not use_system_env: + return True, None + + if not nativefier.is_available(): + return False, self.i18n['missing_dep'].format(dep=bold('nativefier')) + + return True, None def requires_root(self, action: SoftwareAction, pkg: SoftwarePackage) -> bool: return False diff --git a/bauh/view/core/controller.py b/bauh/view/core/controller.py index 70a94a87..ac889b10 100755 --- a/bauh/view/core/controller.py +++ b/bauh/view/core/controller.py @@ -4,7 +4,7 @@ import time import traceback from subprocess import Popen, STDOUT from threading import Thread -from typing import List, Set, Type, Tuple, Dict +from typing import List, Set, Type, Tuple, Dict, Optional from bauh.api.abstract.controller import SoftwareManager, SearchResult, ApplicationContext, UpgradeRequirements, \ UpgradeRequirement, TransactionResult, SoftwareAction @@ -119,20 +119,19 @@ class GenericSoftwareManager(SoftwareManager): return res def _can_work(self, man: SoftwareManager): - if self._available_cache is not None: available = False for t in man.get_managed_types(): available = self._available_cache.get(t) if available is None: - available = man.is_enabled() and man.can_work() + available = man.is_enabled() and man.can_work()[0] self._available_cache[t] = available if available: available = True else: - available = man.is_enabled() and man.can_work() + available = man.is_enabled() and man.can_work()[0] if available: if man not in self.working_managers: @@ -198,8 +197,8 @@ class GenericSoftwareManager(SoftwareManager): def set_enabled(self, enabled: bool): pass - def can_work(self) -> bool: - return True + def can_work(self) -> Tuple[bool, Optional[str]]: + return True, None def _get_package_lower_name(self, pkg: SoftwarePackage): return pkg.name.lower() diff --git a/bauh/view/core/downloader.py b/bauh/view/core/downloader.py index a53f7718..0d61d5b0 100644 --- a/bauh/view/core/downloader.py +++ b/bauh/view/core/downloader.py @@ -7,7 +7,7 @@ import traceback from io import StringIO from math import floor from threading import Thread -from typing import Iterable, List +from typing import Iterable, List, Tuple from bauh.api.abstract.download import FileDownloader from bauh.api.abstract.handler import ProcessWatcher @@ -223,3 +223,6 @@ class AdaptableFileDownloader(FileDownloader): def list_available_multithreaded_clients(self) -> List[str]: return [c for c in self.supported_multithread_clients if self.is_multithreaded_client_available(c)] + + def get_supported_clients(self) -> tuple: + return 'wget', 'aria2', 'axel' diff --git a/bauh/view/core/settings.py b/bauh/view/core/settings.py index b75e23e5..4244070b 100644 --- a/bauh/view/core/settings.py +++ b/bauh/view/core/settings.py @@ -39,23 +39,26 @@ class GenericSettingsManager: gem_opts, def_gem_opts, gem_tabs = [], set(), [] for man in self.managers: - if man.can_work(): - man_comp = man.get_settings(screen_width, screen_height) - modname = man.__module__.split('.')[-2] - icon_path = "{r}/gems/{n}/resources/img/{n}.svg".format(r=ROOT_DIR, n=modname) + can_work, reason_not_work = man.can_work() + modname = man.__module__.split('.')[-2] + icon_path = "{r}/gems/{n}/resources/img/{n}.svg".format(r=ROOT_DIR, n=modname) - if man_comp: - tab_name = self.i18n.get('gem.{}.label'.format(modname), modname.capitalize()) - gem_tabs.append(TabComponent(label=tab_name, content=man_comp, icon_path=icon_path, id_=modname)) + man_comp = man.get_settings(screen_width, screen_height) if can_work else None + if man_comp: + tab_name = self.i18n.get('gem.{}.label'.format(modname), modname.capitalize()) + gem_tabs.append(TabComponent(label=tab_name, content=man_comp, icon_path=icon_path, id_=modname)) - opt = InputOption(label=self.i18n.get('gem.{}.label'.format(modname), modname.capitalize()), - tooltip=self.i18n.get('gem.{}.info'.format(modname)), - value=modname, - icon_path='{r}/gems/{n}/resources/img/{n}.svg'.format(r=ROOT_DIR, n=modname)) - gem_opts.append(opt) + help_tip = reason_not_work if not can_work and reason_not_work else self.i18n.get(f'gem.{modname}.info') + opt = InputOption(label=self.i18n.get('gem.{}.label'.format(modname), modname.capitalize()), + tooltip=help_tip, + value=modname, + icon_path='{r}/gems/{n}/resources/img/{n}.svg'.format(r=ROOT_DIR, n=modname), + read_only=not can_work, + extra_properties={'warning': 'true'} if not can_work else None) + gem_opts.append(opt) - if man.is_enabled() and man in self.working_managers: - def_gem_opts.add(opt) + if man.is_enabled() and man in self.working_managers: + def_gem_opts.add(opt) core_config = self.configman.get_config() diff --git a/bauh/view/qt/components.py b/bauh/view/qt/components.py index ac5b8072..6c0cec62 100644 --- a/bauh/view/qt/components.py +++ b/bauh/view/qt/components.py @@ -275,6 +275,10 @@ class RadioButtonQt(QRadioButton): self.setAttribute(Qt.WA_TransparentForMouseEvents) self.setFocusPolicy(Qt.NoFocus) + if model.extra_properties: + for name, val in model.extra_properties.items(): + self.setProperty(name, val) + def _set_checked(self, checked: bool): if checked: self.model_parent.value = self.model @@ -303,6 +307,10 @@ class CheckboxQt(QCheckBox): else: self.setCursor(QCursor(Qt.PointingHandCursor)) + if model.extra_properties: + for name, val in model.extra_properties.items(): + self.setProperty(name, val) + def _set_checked(self, state): checked = state == 2 @@ -541,7 +549,12 @@ class MultipleSelectQt(QGroupBox): if op.tooltip: help_icon = QLabel() - help_icon.setProperty('help_icon', 'true') + + if op.extra_properties and op.extra_properties.get('warning') == 'true': + help_icon.setProperty('warning_icon', 'true') + else: + help_icon.setProperty('help_icon', 'true') + help_icon.setCursor(QCursor(Qt.WhatsThisCursor)) help_icon.setToolTip(op.tooltip) widget.layout().addWidget(help_icon) @@ -596,7 +609,12 @@ class FormMultipleSelectQt(QWidget): if op.tooltip: help_icon = QLabel() - help_icon.setProperty('help_icon', 'true') + + if op.extra_properties and op.extra_properties.get('warning') == 'true': + help_icon.setProperty('warning_icon', 'true') + else: + help_icon.setProperty('help_icon', 'true') + help_icon.setToolTip(op.tooltip) help_icon.setCursor(QCursor(Qt.WhatsThisCursor)) widget.layout().addWidget(help_icon) diff --git a/bauh/view/resources/locale/ca b/bauh/view/resources/locale/ca index 6130cc83..c8707435 100644 --- a/bauh/view/resources/locale/ca +++ b/bauh/view/resources/locale/ca @@ -347,6 +347,7 @@ manage_window.upgrade_all.popup.title=Actualitza message.file.not_exist=Fitxer no existeix message.file.not_exist.body=El fitxer {} sembla no existir mirror=mirall +missing_dep={dep} is not installed name=nom no=no not_installed=no instal·lada diff --git a/bauh/view/resources/locale/de b/bauh/view/resources/locale/de index 25810101..dda94c79 100644 --- a/bauh/view/resources/locale/de +++ b/bauh/view/resources/locale/de @@ -346,6 +346,7 @@ manage_window.upgrade_all.popup.title=Upgrade message.file.not_exist=Datei existiert nicht message.file.not_exist.body=Die Datei {} scheint nicht zu existieren mirror=mirror +missing_dep={dep} is not installed name=Name no=Nein not_installed=nicht installiert diff --git a/bauh/view/resources/locale/en b/bauh/view/resources/locale/en index b34f41bf..c4668f63 100644 --- a/bauh/view/resources/locale/en +++ b/bauh/view/resources/locale/en @@ -347,6 +347,7 @@ manage_window.upgrade_all.popup.title=Upgrade message.file.not_exist.body=The file {} seems not to exist message.file.not_exist=File does not exist mirror=mirror +missing_dep={dep} is not installed name=name no=no not_installed=not installed diff --git a/bauh/view/resources/locale/es b/bauh/view/resources/locale/es index 4f1b179a..8f27bbb2 100644 --- a/bauh/view/resources/locale/es +++ b/bauh/view/resources/locale/es @@ -348,6 +348,7 @@ manage_window.upgrade_all.popup.title=Actualizar message.file.not_exist=Archivo no existe message.file.not_exist.body=El archivo {} parece no existir mirror=espejo +missing_dep={dep} no está instalado name=nombre no=no not_installed=no instalada diff --git a/bauh/view/resources/locale/fr b/bauh/view/resources/locale/fr index 449e17a9..c94b0836 100644 --- a/bauh/view/resources/locale/fr +++ b/bauh/view/resources/locale/fr @@ -343,6 +343,7 @@ manage_window.upgrade_all.popup.title=Mettre à jour message.file.not_exist.body=Le fichier {} n'a pas l'air d'exister message.file.not_exist=Fichier inexistant mirror=mirroir +missing_dep={dep} is not installed name=nom no=non not_installed=pas installé diff --git a/bauh/view/resources/locale/it b/bauh/view/resources/locale/it index 5d764ba1..6bf8c1b3 100644 --- a/bauh/view/resources/locale/it +++ b/bauh/view/resources/locale/it @@ -348,6 +348,7 @@ manage_window.upgrade_all.popup.title=Aggiorna message.file.not_exist=File non esiste message.file.not_exist.body=Il file {} sembra non esistere mirror=specchio +missing_dep={dep} is not installed name=nome no=no not_installed=non installato diff --git a/bauh/view/resources/locale/pt b/bauh/view/resources/locale/pt index b185674a..a8a3510e 100644 --- a/bauh/view/resources/locale/pt +++ b/bauh/view/resources/locale/pt @@ -347,6 +347,7 @@ manage_window.upgrade_all.popup.title=Atualizar message.file.not_exist.body=O arquivo {} parece não existir message.file.not_exist=Arquivo não existe mirror=espelho +missing_dep={dep} não está instalado name=nome no=não not_installed=não instalado diff --git a/bauh/view/resources/locale/ru b/bauh/view/resources/locale/ru index 7def1dab..db9188e2 100644 --- a/bauh/view/resources/locale/ru +++ b/bauh/view/resources/locale/ru @@ -346,6 +346,7 @@ manage_window.upgrade_all.popup.title=Обновление message.file.not_exist=Файл не существует message.file.not_exist.body=Файл {}, кажется, не существует mirror=Зеркало +missing_dep={dep} is not installed name=Имя no=Нет not_installed=Не установлено diff --git a/bauh/view/resources/locale/tr b/bauh/view/resources/locale/tr index 00406ce9..6250f3d1 100644 --- a/bauh/view/resources/locale/tr +++ b/bauh/view/resources/locale/tr @@ -346,6 +346,7 @@ manage_window.upgrade_all.popup.title=Yükselt message.file.not_exist.body={} Dosyası yok gibi görünüyor message.file.not_exist=Dosya bulunamuyor mirror=yansı +missing_dep={dep} is not installed name=isim no=hayır not_installed=yüklü değil diff --git a/bauh/view/resources/style/darcula/darcula.qss b/bauh/view/resources/style/darcula/darcula.qss index c662c20f..9996ec5f 100644 --- a/bauh/view/resources/style/darcula/darcula.qss +++ b/bauh/view/resources/style/darcula/darcula.qss @@ -20,6 +20,10 @@ QCheckBox::indicator:checked:disabled { image: url("@style_dir/img/checkbox_checked_disabled.svg"); } +QCheckBox[warning = "true"] { + color: @color.warning; +} + QLineEdit:disabled, QComboBox:disabled, QSpinBox:disabled { color: @disabled.color; } @@ -408,6 +412,10 @@ QLabel[help_icon = "true"] { qproperty-pixmap: url("@style_dir/img/help.svg"); } +QLabel[warning_icon = "true"] { + qproperty-pixmap: url("@style_dir/img/warning.svg"); +} + QLabel[tip_icon = "true"] { qproperty-pixmap: url("@style_dir/img/help.svg"); } diff --git a/bauh/view/resources/style/darcula/img/warning.svg b/bauh/view/resources/style/darcula/img/warning.svg new file mode 100644 index 00000000..31c505ed --- /dev/null +++ b/bauh/view/resources/style/darcula/img/warning.svg @@ -0,0 +1,122 @@ + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bauh/view/resources/style/default/default.qss b/bauh/view/resources/style/default/default.qss index 1d3f55b9..fb7ab7ca 100644 --- a/bauh/view/resources/style/default/default.qss +++ b/bauh/view/resources/style/default/default.qss @@ -28,6 +28,10 @@ QCheckBox::indicator { height: 18px; } +QCheckBox[warning = "true"] { + color: yellow; +} + QProgressBar { max-height: 4px; } @@ -54,7 +58,7 @@ QMenu QPushButton { text-align: left; } -QLabel[help_icon = "true"] { +QLabel[help_icon = "true"], QLabel[warning_icon = "true"] { qproperty-scaledContents: True; min-height: 16; max-height: 16; diff --git a/bauh/view/resources/style/light/img/warning.svg b/bauh/view/resources/style/light/img/warning.svg new file mode 100644 index 00000000..6f7831e9 --- /dev/null +++ b/bauh/view/resources/style/light/img/warning.svg @@ -0,0 +1,122 @@ + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bauh/view/resources/style/light/light.qss b/bauh/view/resources/style/light/light.qss index b0db2bac..b8f0f3c0 100644 --- a/bauh/view/resources/style/light/light.qss +++ b/bauh/view/resources/style/light/light.qss @@ -39,6 +39,10 @@ QCheckBox::indicator:checked:disabled { image: url("@style_dir/img/checkbox_checked_disabled.svg"); } +QCheckBox[warning = "true"] { + color: @color.red; +} + QMenu QPushButton:hover { background-color: @menu.item.selected.background.color; } @@ -67,6 +71,10 @@ QLabel[help_icon = "true"] { qproperty-pixmap: url("@style_dir/img/help.svg"); } +QLabel[warning_icon = "true"] { + qproperty-pixmap: url("@style_dir/img/warning.svg"); +} + QLabel[tip_icon = "true"] { qproperty-pixmap: url("@style_dir/img/help.svg"); } diff --git a/bauh/view/resources/style/sublime/img/warning.svg b/bauh/view/resources/style/sublime/img/warning.svg new file mode 100644 index 00000000..c18225db --- /dev/null +++ b/bauh/view/resources/style/sublime/img/warning.svg @@ -0,0 +1,122 @@ + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bauh/view/resources/style/sublime/sublime.qss b/bauh/view/resources/style/sublime/sublime.qss index 019bdb56..d8b966c3 100644 --- a/bauh/view/resources/style/sublime/sublime.qss +++ b/bauh/view/resources/style/sublime/sublime.qss @@ -47,6 +47,10 @@ QCheckBox::indicator:checked:disabled { image: url("@style_dir/img/checkbox_checked_disabled.svg"); } +QCheckBox[warning = "true"] { + color: @color.yellow; +} + QComboBox, QComboBox QAbstractItemView, QMenu QAbstractItemView { selection-background-color: @menu.item.selected.background.color; selection-color: @menu.item.selected.font.color; @@ -115,6 +119,10 @@ QLabel[help_icon = "true"] { qproperty-pixmap: url("@style_dir/img/help.svg"); } +QLabel[warning_icon = "true"] { + qproperty-pixmap: url("@style_dir/img/warning.svg"); +} + QLabel[tip_icon = "true"] { qproperty-pixmap: url("@style_dir/img/help.svg"); }