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 @@
+
+
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 @@
+
+
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 @@
+
+
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");
}