mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-06 21:44:16 +02:00
restart is not required when changing enabled gems
This commit is contained in:
17
CHANGELOG.md
17
CHANGELOG.md
@@ -4,18 +4,33 @@ 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.6.0]
|
||||
## [0.6.0] 2019-09-
|
||||
### Features
|
||||
- Theme / style selector via UI (environment variable / parameter BAUH_THEME (--theme) removed)
|
||||
- New "Installed" button: quickly retrieves the installed packages without a full refresh
|
||||
- Now it is possible to enable / disable the packaging technologies via graphical interface using the "Application types" action in the lower "Settings" menu.
|
||||
- Supporting AUR packages (install, uninstall, search, info, downgrade and history)
|
||||
|
||||
### Improvements:
|
||||
- Reading installed Snaps now takes around 95% less time.
|
||||
- Reading installed Flatpaks now takes around 45% less time.
|
||||
- Refreshing only the associated package type after a successful operation (install, uninstall, downgrade, ...)
|
||||
- Progress bar status can now be controlled by the software manager while an operation is being executed
|
||||
|
||||
### UI Changes
|
||||
- "Upgrade selected" and "Refresh" buttons now have text labels and new colors
|
||||
- Updates warning icon removed
|
||||
- Publisher / maintainer column
|
||||
- Progress bar height reduced
|
||||
- New "Application settings" buttons located in right lower corner
|
||||
|
||||
### Fixes:
|
||||
- cached Flatpak app current version
|
||||
|
||||
### Code
|
||||
- Code was internally modularized as: "api" (conceptual classes used to create custom software managers), "gems" (software managers), "commons" (common classes shared between the UI and "gems")
|
||||
- API allows custom operations (Snap "refresh" was refactored as a custom operation)
|
||||
|
||||
|
||||
## [0.5.2] 2019-09-06
|
||||
### Features
|
||||
|
||||
@@ -134,10 +134,24 @@ class SoftwareManager(ABC):
|
||||
@abstractmethod
|
||||
def is_enabled(self) -> bool:
|
||||
"""
|
||||
:return: if the instance is available to perform actions
|
||||
:return: if the instance is enabled
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def set_enabled(self, enabled: bool):
|
||||
"""
|
||||
:param enabled:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def can_work(self) -> bool:
|
||||
"""
|
||||
:return: if the instance can work based on what is installed in the user's machine.
|
||||
"""
|
||||
|
||||
def cache_to_disk(self, pkg: SoftwarePackage, icon_bytes: bytes, only_icon: bool):
|
||||
"""
|
||||
Saves the package data to the hard disk.
|
||||
|
||||
@@ -28,7 +28,7 @@ class InputOption:
|
||||
Represents a select component option.
|
||||
"""
|
||||
|
||||
def __init__(self, label: str, value: str, tooltip: str = None, icon_path: str = None):
|
||||
def __init__(self, label: str, value: object, tooltip: str = None, icon_path: str = None):
|
||||
"""
|
||||
:param label: the string that will be shown to the user
|
||||
:param value: the option value (not shown)
|
||||
|
||||
65
bauh/app.py
65
bauh/app.py
@@ -11,7 +11,6 @@ from bauh.core.controller import GenericSoftwareManager
|
||||
from bauh.util import util, logs, resource
|
||||
from bauh.util.cache import DefaultMemoryCacheFactory, CacheCleaner
|
||||
from bauh.util.disk import DefaultDiskCacheLoaderFactory
|
||||
from bauh.view.qt.gem_selector import GemSelectorPanel
|
||||
from bauh.view.qt.systray import TrayIcon
|
||||
from bauh.view.qt.window import ManageWindow
|
||||
|
||||
@@ -46,47 +45,37 @@ else:
|
||||
if app.style().objectName().lower() not in {'fusion', 'breeze'}:
|
||||
app.setStyle('Fusion')
|
||||
|
||||
if not user_config.gems:
|
||||
managers = gems.load_managers(context=context, locale=args.locale)
|
||||
else:
|
||||
managers = gems.load_managers(context=context, locale=args.locale, names=user_config.gems)
|
||||
managers = gems.load_managers(context=context, locale=args.locale, enabled_gems=user_config.enabled_gems if user_config.enabled_gems else None)
|
||||
|
||||
enabled_managers = [m for m in managers if m.is_enabled()]
|
||||
manager = GenericSoftwareManager(managers, context=context, app_args=args)
|
||||
manager.prepare()
|
||||
|
||||
if not user_config.gems and enabled_managers and not args.tray:
|
||||
gem_panel = GemSelectorPanel(enabled_managers, i18n, managers_set=None)
|
||||
gem_panel.show()
|
||||
else:
|
||||
manager = GenericSoftwareManager(enabled_managers, context=context, app_args=args)
|
||||
manager.prepare()
|
||||
|
||||
manage_window = ManageWindow(i18n=i18n,
|
||||
manager=manager,
|
||||
icon_cache=icon_cache,
|
||||
disk_cache=args.disk_cache,
|
||||
download_icons=bool(args.download_icons),
|
||||
screen_size=app.primaryScreen().size(),
|
||||
suggestions=args.sugs,
|
||||
display_limit=args.max_displayed,
|
||||
config=user_config,
|
||||
context=context)
|
||||
|
||||
if args.tray:
|
||||
tray_icon = TrayIcon(locale_keys=i18n,
|
||||
manage_window = ManageWindow(i18n=i18n,
|
||||
manager=manager,
|
||||
manage_window=manage_window,
|
||||
check_interval=args.check_interval,
|
||||
update_notification=bool(args.update_notification),
|
||||
config=user_config)
|
||||
manage_window.set_tray_icon(tray_icon)
|
||||
tray_icon.show()
|
||||
icon_cache=icon_cache,
|
||||
disk_cache=args.disk_cache,
|
||||
download_icons=bool(args.download_icons),
|
||||
screen_size=app.primaryScreen().size(),
|
||||
suggestions=args.sugs,
|
||||
display_limit=args.max_displayed,
|
||||
config=user_config,
|
||||
context=context)
|
||||
|
||||
if args.show_panel:
|
||||
tray_icon.show_manage_window()
|
||||
else:
|
||||
manage_window.refresh_apps()
|
||||
manage_window.show()
|
||||
if args.tray:
|
||||
tray_icon = TrayIcon(locale_keys=i18n,
|
||||
manager=manager,
|
||||
manage_window=manage_window,
|
||||
check_interval=args.check_interval,
|
||||
update_notification=bool(args.update_notification),)
|
||||
manage_window.set_tray_icon(tray_icon)
|
||||
tray_icon.show()
|
||||
|
||||
cache_cleaner.start()
|
||||
if args.show_panel:
|
||||
tray_icon.show_manage_window()
|
||||
else:
|
||||
manage_window.refresh_apps()
|
||||
manage_window.show()
|
||||
|
||||
cache_cleaner.start()
|
||||
|
||||
sys.exit(app.exec_())
|
||||
|
||||
@@ -12,8 +12,8 @@ FILE_PATH = '{}/config.json'.format(CONFIG_PATH)
|
||||
|
||||
class Configuration:
|
||||
|
||||
def __init__(self, gems: List[str] = None, style: str = None):
|
||||
self.gems = gems
|
||||
def __init__(self, enabled_gems: List[str] = None, style: str = None):
|
||||
self.enabled_gems = enabled_gems
|
||||
self.style = style
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ def read() -> Configuration:
|
||||
|
||||
return Configuration(**json.loads(config_file))
|
||||
|
||||
return Configuration(gems=None)
|
||||
return Configuration()
|
||||
|
||||
|
||||
def save(config: Configuration):
|
||||
|
||||
@@ -16,11 +16,15 @@ class GenericSoftwareManager(SoftwareManager):
|
||||
super(GenericSoftwareManager, self).__init__(context=context)
|
||||
self.managers = managers
|
||||
self.map = {t: m for m in self.managers for t in m.get_managed_types()}
|
||||
self._enabled_map = {} if app_args.check_packaging_once else None
|
||||
self._available_map = {} if app_args.check_packaging_once else None
|
||||
self.thread_prepare = None
|
||||
self.i18n = context.i18n
|
||||
self.disk_loader_factory = context.disk_loader_factory
|
||||
|
||||
def reset_cache(self):
|
||||
if self._available_map is not None:
|
||||
self._available_map = {}
|
||||
|
||||
def _sort(self, apps: List[SoftwarePackage], word: str) -> List[SoftwarePackage]:
|
||||
|
||||
exact_name_matches, contains_name_matches, others = [], [], []
|
||||
@@ -42,21 +46,21 @@ class GenericSoftwareManager(SoftwareManager):
|
||||
|
||||
return res
|
||||
|
||||
def _is_enabled(self, man: SoftwareManager):
|
||||
def _can_work(self, man: SoftwareManager):
|
||||
|
||||
if self._enabled_map is not None:
|
||||
enabled = self._enabled_map.get(man.get_managed_types())
|
||||
if self._available_map is not None:
|
||||
enabled = self._available_map.get(man.get_managed_types())
|
||||
|
||||
if enabled is None:
|
||||
enabled = man.is_enabled()
|
||||
self._enabled_map[man.get_managed_types()] = enabled
|
||||
enabled = man.is_enabled() and man.can_work()
|
||||
self._available_map[man.get_managed_types()] = enabled
|
||||
|
||||
return enabled
|
||||
else:
|
||||
return man.is_enabled()
|
||||
return man.is_enabled() and man.can_work()
|
||||
|
||||
def _search(self, word: str, man: SoftwareManager, disk_loader, res: SearchResult):
|
||||
if self._is_enabled(man):
|
||||
if self._can_work(man):
|
||||
apps_found = man.search(words=word, disk_loader=disk_loader)
|
||||
res.installed.extend(apps_found.installed)
|
||||
res.new.extend(apps_found.new)
|
||||
@@ -95,6 +99,12 @@ class GenericSoftwareManager(SoftwareManager):
|
||||
self.thread_prepare.join()
|
||||
self.thread_prepare = None
|
||||
|
||||
def set_enabled(self, enabled: bool):
|
||||
pass
|
||||
|
||||
def can_work(self) -> bool:
|
||||
return True
|
||||
|
||||
def read_installed(self, disk_loader: DiskCacheLoader = None, limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None) -> SearchResult:
|
||||
self._wait_to_be_ready()
|
||||
|
||||
@@ -104,7 +114,7 @@ class GenericSoftwareManager(SoftwareManager):
|
||||
|
||||
if not pkg_types: # any type
|
||||
for man in self.managers:
|
||||
if self._is_enabled(man):
|
||||
if self._can_work(man):
|
||||
if not disk_loader:
|
||||
disk_loader = self.disk_loader_factory.new()
|
||||
disk_loader.start()
|
||||
@@ -117,7 +127,7 @@ class GenericSoftwareManager(SoftwareManager):
|
||||
|
||||
for t in pkg_types:
|
||||
man = self.map.get(t)
|
||||
if man and (man not in man_already_used) and self._is_enabled(man):
|
||||
if man and (man not in man_already_used) and self._can_work(man):
|
||||
|
||||
if not disk_loader:
|
||||
disk_loader = self.disk_loader_factory.new()
|
||||
@@ -185,7 +195,7 @@ class GenericSoftwareManager(SoftwareManager):
|
||||
|
||||
def _get_manager_for(self, app: SoftwarePackage) -> SoftwareManager:
|
||||
man = self.map[app.__class__]
|
||||
return man if man and self._is_enabled(man) else None
|
||||
return man if man and self._can_work(man) else None
|
||||
|
||||
def cache_to_disk(self, app: SoftwarePackage, icon_bytes: bytes, only_icon: bool):
|
||||
if self.context.disk_cache and app.supports_disk_cache():
|
||||
@@ -211,7 +221,7 @@ class GenericSoftwareManager(SoftwareManager):
|
||||
def _prepare(self):
|
||||
if self.managers:
|
||||
for man in self.managers:
|
||||
if self._is_enabled(man):
|
||||
if self._can_work(man):
|
||||
man.prepare()
|
||||
|
||||
def prepare(self):
|
||||
@@ -225,7 +235,7 @@ class GenericSoftwareManager(SoftwareManager):
|
||||
|
||||
if self.managers:
|
||||
for man in self.managers:
|
||||
if self._is_enabled(man):
|
||||
if self._can_work(man):
|
||||
man_updates = man.list_updates()
|
||||
if man_updates:
|
||||
updates.extend(man_updates)
|
||||
@@ -248,7 +258,7 @@ class GenericSoftwareManager(SoftwareManager):
|
||||
return warnings
|
||||
|
||||
def _fill_suggestions(self, suggestions: list, man: SoftwareManager, limit: int):
|
||||
if self._is_enabled(man):
|
||||
if self._can_work(man):
|
||||
man_sugs = man.list_suggestions(limit)
|
||||
|
||||
if man_sugs:
|
||||
|
||||
@@ -19,11 +19,11 @@ def find_manager(member):
|
||||
return manager_found
|
||||
|
||||
|
||||
def load_managers(locale: str, context: ApplicationContext, names: List[str] = None) -> List[SoftwareManager]:
|
||||
def load_managers(locale: str, context: ApplicationContext, enabled_gems: List[str] = None) -> List[SoftwareManager]:
|
||||
managers = []
|
||||
|
||||
for f in os.scandir(ROOT_DIR + '/gems'):
|
||||
if f.is_dir() and f.name != '__pycache__' and (not names or f.name in names):
|
||||
if f.is_dir() and f.name != '__pycache__':
|
||||
module = pkgutil.find_loader('bauh.gems.{}.controller'.format(f.name)).load_module()
|
||||
|
||||
manager_class = find_manager(module)
|
||||
@@ -35,7 +35,12 @@ def load_managers(locale: str, context: ApplicationContext, names: List[str] = N
|
||||
if os.path.exists(locale_path):
|
||||
context.i18n.update(util.get_locale_keys(locale, locale_path))
|
||||
|
||||
managers.append(manager_class(context=context))
|
||||
man = manager_class(context=context)
|
||||
|
||||
if enabled_gems is not None and f.name not in enabled_gems:
|
||||
man.set_enabled(False)
|
||||
|
||||
managers.append(man)
|
||||
|
||||
return managers
|
||||
|
||||
|
||||
@@ -11,13 +11,12 @@ from bauh.api.abstract.disk import DiskCacheLoader
|
||||
from bauh.api.abstract.handler import ProcessWatcher
|
||||
from bauh.api.abstract.model import PackageUpdate, PackageHistory, SoftwarePackage, PackageSuggestion, PackageStatus
|
||||
from bauh.api.abstract.view import MessageType
|
||||
from bauh.commons.html import bold
|
||||
from bauh.commons.system import SystemProcess, ProcessHandler, new_subprocess, run_cmd, new_root_subprocess
|
||||
|
||||
from bauh.gems.arch import BUILD_DIR, aur, pacman, makepkg, pkgbuild, message, confirmation, disk, git, suggestions
|
||||
from bauh.gems.arch.aur import AURClient
|
||||
from bauh.gems.arch.mapper import ArchDataMapper
|
||||
from bauh.gems.arch.model import ArchPackage
|
||||
from bauh.commons.html import bold
|
||||
from bauh.gems.arch.worker import AURIndexUpdater, ArchDiskCacheUpdater
|
||||
|
||||
URL_GIT = 'https://aur.archlinux.org/{}.git'
|
||||
@@ -41,6 +40,7 @@ class ArchManager(SoftwareManager):
|
||||
self.aur_index_updater = AURIndexUpdater(context, self)
|
||||
self.dcache_updater = ArchDiskCacheUpdater(context.logger)
|
||||
self.logger = context.logger
|
||||
self.enabled = True
|
||||
|
||||
def _upgrade_search_result(self, apidata: dict, installed_pkgs: dict, downgrade_enabled: bool, res: SearchResult, disk_loader: DiskCacheLoader):
|
||||
app = self.mapper.map_api_data(apidata, installed_pkgs['not_signed'])
|
||||
@@ -510,6 +510,12 @@ class ArchManager(SoftwareManager):
|
||||
return False
|
||||
|
||||
def is_enabled(self) -> bool:
|
||||
return self.enabled
|
||||
|
||||
def set_enabled(self, enabled: bool):
|
||||
self.enabled = enabled
|
||||
|
||||
def can_work(self) -> bool:
|
||||
try:
|
||||
return pacman.is_enabled() and self._is_wget_available()
|
||||
except FileNotFoundError:
|
||||
|
||||
@@ -21,6 +21,7 @@ class FlatpakManager(SoftwareManager):
|
||||
self.i18n = context.i18n
|
||||
self.api_cache = context.cache_factory.new()
|
||||
context.disk_loader_factory.map(FlatpakApplication, self.api_cache)
|
||||
self.enabled = True
|
||||
|
||||
def get_managed_types(self) -> Set["type"]:
|
||||
return {FlatpakApplication}
|
||||
@@ -145,6 +146,12 @@ class FlatpakManager(SoftwareManager):
|
||||
return ProcessHandler(watcher).handle(SystemProcess(subproc=flatpak.install(pkg.id, pkg.origin)))
|
||||
|
||||
def is_enabled(self):
|
||||
return self.enabled
|
||||
|
||||
def set_enabled(self, enabled: bool):
|
||||
self.enabled = enabled
|
||||
|
||||
def can_work(self) -> bool:
|
||||
return flatpak.is_installed()
|
||||
|
||||
def requires_root(self, action: str, pkg: FlatpakApplication):
|
||||
|
||||
@@ -18,6 +18,7 @@ class SnapManager(SoftwareManager):
|
||||
self.i18n = context.i18n
|
||||
self.api_cache = context.cache_factory.new()
|
||||
context.disk_loader_factory.map(SnapApplication, self.api_cache)
|
||||
self.enabled = True
|
||||
|
||||
def map_json(self, app_json: dict, installed: bool, disk_loader: DiskCacheLoader) -> SnapApplication:
|
||||
app = SnapApplication(publisher=app_json.get('publisher'),
|
||||
@@ -108,6 +109,12 @@ class SnapManager(SoftwareManager):
|
||||
return ProcessHandler(watcher).handle(SystemProcess(subproc=snap.install_and_stream(pkg.name, pkg.confinement, root_password)))
|
||||
|
||||
def is_enabled(self) -> bool:
|
||||
return self.enabled
|
||||
|
||||
def set_enabled(self, enabled: bool):
|
||||
self.enabled = enabled
|
||||
|
||||
def can_work(self) -> bool:
|
||||
return snap.is_installed()
|
||||
|
||||
def requires_root(self, action: str, pkg: SnapApplication):
|
||||
|
||||
@@ -101,7 +101,7 @@ any=any
|
||||
manage_window.name_filter.tooltip=Type here to filter apps by name
|
||||
manage_window.name_filter.placeholder=Filter by name
|
||||
publisher=publisher
|
||||
publisher.unknown=unknown publisher
|
||||
unknown=unknown
|
||||
welcome=welcome
|
||||
gem_selector.title=Application types
|
||||
gem_selector.question=What types of applications do you want to find here ?
|
||||
|
||||
@@ -103,7 +103,7 @@ any=cualquier
|
||||
manage_window.name_filter.tooltip=Escriba aquí para filtrar aplicaciones por nombre
|
||||
manage_window.name_filter.placeholder=Filtrar por nombre
|
||||
publisher=publicador
|
||||
publisher.unknown=publicador desconocido
|
||||
unknown=desconocido
|
||||
welcome=bienvenido
|
||||
gem_selector.title=Tipos de aplicativos
|
||||
gem_selector.question=¿Qué tipos de aplicativos quieres encontrar aquí?
|
||||
|
||||
@@ -103,7 +103,7 @@ any=qualquer
|
||||
manage_window.name_filter.tooltip=Digite aqui para filtrar aplicativos pelo nome
|
||||
manage_window.name_filter.placeholder=Filtrar por nome
|
||||
publisher=publicador
|
||||
publisher.unknown=publicador desconhecido
|
||||
unknown=desconhecido
|
||||
welcome=bem vindo
|
||||
gem_selector.title=Tipos de aplicativos
|
||||
gem_selector.question=Quais tipos de aplicativos você quer encontrar por aqui ?
|
||||
|
||||
@@ -335,7 +335,7 @@ class AppsTable(QTableWidget):
|
||||
desc = '...'
|
||||
|
||||
if desc and desc != '...':
|
||||
desc = strip_html(desc[0:25]) + '...'
|
||||
desc = strip_html(desc[0:40]) + '...'
|
||||
|
||||
item.setText(desc)
|
||||
|
||||
@@ -359,9 +359,9 @@ class AppsTable(QTableWidget):
|
||||
|
||||
if not publisher:
|
||||
if not pkg.model.installed:
|
||||
item.setStyleSheet('QLabel { color: red; font-weight: bold}')
|
||||
item.setStyleSheet('QLabel { color: red; }')
|
||||
|
||||
publisher = '({})'.format(self.i18n['publisher.unknown'])
|
||||
publisher = self.i18n['unknown']
|
||||
|
||||
item.setText(' {} '.format(publisher))
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ def update_info(pkgv: PackageView, pkgs_info: dict):
|
||||
|
||||
|
||||
def apply_filters(pkgv: PackageView, filters: dict, info: dict):
|
||||
hidden = filters['only_apps'] and not pkgv.model.is_application()
|
||||
hidden = filters['only_apps'] and pkgv.model.installed and not pkgv.model.is_application()
|
||||
|
||||
if not hidden and filters['type'] is not None and filters['type'] != 'any':
|
||||
hidden = pkgv.model.get_type() != filters['type']
|
||||
|
||||
@@ -2,6 +2,7 @@ from typing import List
|
||||
|
||||
from PyQt5.QtWidgets import QMessageBox, QVBoxLayout, QLabel, QWidget
|
||||
from bauh.api.abstract.view import ViewComponent, SingleSelectComponent, MultipleSelectComponent
|
||||
from bauh.view.qt import css
|
||||
|
||||
from bauh.view.qt.components import MultipleSelectQt, new_single_select
|
||||
|
||||
@@ -13,6 +14,7 @@ class ConfirmationDialog(QMessageBox):
|
||||
self.setWindowTitle(title)
|
||||
self.setStyleSheet('QLabel { margin-right: 25px; }')
|
||||
self.bt_yes = self.addButton(locale_keys['popup.button.yes'] if not confirmation_label else confirmation_label.capitalize(), QMessageBox.YesRole)
|
||||
self.bt_yes.setStyleSheet(css.OK_BUTTON)
|
||||
|
||||
self.addButton(locale_keys['popup.button.no'] if not deny_label else deny_label.capitalize(), QMessageBox.NoRole)
|
||||
|
||||
|
||||
4
bauh/view/qt/css.py
Normal file
4
bauh/view/qt/css.py
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
OK_BUTTON = """QPushButton { background: green; color: white; font-weight: bold}
|
||||
QPushButton:disabled { background-color: gray; }
|
||||
"""
|
||||
@@ -5,6 +5,7 @@ from PyQt5.QtWidgets import QMessageBox, QLabel, QWidget, QHBoxLayout
|
||||
from bauh.api.abstract.view import MessageType
|
||||
|
||||
from bauh.util import resource
|
||||
from bauh.view.qt import css
|
||||
|
||||
MSG_TYPE_MAP = {
|
||||
MessageType.ERROR: QMessageBox.Critical,
|
||||
@@ -42,6 +43,7 @@ def ask_confirmation(title: str, body: str, locale_keys: dict, icon: QIcon = QIc
|
||||
diag.layout().addWidget(wbody, 0, 1)
|
||||
|
||||
bt_yes = diag.addButton(locale_keys['popup.button.yes'], QMessageBox.YesRole)
|
||||
bt_yes.setStyleSheet(css.OK_BUTTON)
|
||||
|
||||
diag.addButton(locale_keys['popup.button.no'], QMessageBox.NoRole)
|
||||
|
||||
|
||||
@@ -1,57 +1,53 @@
|
||||
import subprocess
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
from PyQt5.QtCore import Qt, QCoreApplication
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QWidget, QLabel, QGridLayout, QPushButton
|
||||
|
||||
from bauh import ROOT_DIR
|
||||
from bauh.api.abstract.controller import SoftwareManager
|
||||
from bauh.api.abstract.view import MultipleSelectComponent, InputOption
|
||||
from bauh.commons import resource, system
|
||||
from bauh.commons import resource
|
||||
from bauh.core.config import Configuration, save
|
||||
from bauh.util import util
|
||||
from bauh.view.qt import qt_utils
|
||||
from bauh.core.controller import GenericSoftwareManager
|
||||
from bauh.view.qt import qt_utils, css
|
||||
from bauh.view.qt.components import MultipleSelectQt, CheckboxQt, new_spacer
|
||||
|
||||
|
||||
class GemSelectorPanel(QWidget):
|
||||
|
||||
def __init__(self, managers: List[SoftwareManager], i18n: dict, managers_set: List[str], show_panel_after_restart: bool = False):
|
||||
def __init__(self, window: QWidget, manager: GenericSoftwareManager, i18n: dict, config: Configuration, show_panel_after_restart: bool = False):
|
||||
super(GemSelectorPanel, self).__init__()
|
||||
self.managers = managers
|
||||
self.window = window
|
||||
self.manager = manager
|
||||
self.config = config
|
||||
self.setLayout(QGridLayout())
|
||||
self.setWindowIcon(QIcon(resource.get_path('img/logo.svg', ROOT_DIR)))
|
||||
self.setWindowTitle(i18n['welcome'].capitalize() if not managers_set else i18n['gem_selector.title'])
|
||||
self.setWindowTitle(i18n['gem_selector.title'])
|
||||
self.resize(400, 400)
|
||||
self.exit_on_close = not managers_set
|
||||
self.show_panel_after_restart = show_panel_after_restart
|
||||
|
||||
self.label_question = QLabel(i18n['gem_selector.question'])
|
||||
self.label_question.setStyleSheet('QLabel { font-weight: bold}')
|
||||
self.layout().addWidget(self.label_question, 0, 1, Qt.AlignHCenter)
|
||||
|
||||
self.bt_proceed = QPushButton(i18n['proceed' if not managers_set else 'change'].capitalize())
|
||||
self.bt_proceed.setStyleSheet("""QPushButton { background: green; color: white; font-weight: bold}
|
||||
QPushButton:disabled { background-color: gray; }
|
||||
""")
|
||||
self.bt_proceed = QPushButton(i18n['change'].capitalize())
|
||||
self.bt_proceed.setStyleSheet(css.OK_BUTTON)
|
||||
self.bt_proceed.clicked.connect(self.save)
|
||||
|
||||
self.bt_exit = QPushButton(i18n['exit'].capitalize())
|
||||
self.bt_exit.setStyleSheet('QPushButton { background: red; color: white; font-weight: bold}')
|
||||
self.bt_exit.clicked.connect(self.exit)
|
||||
|
||||
self.gem_map = {}
|
||||
gem_options = []
|
||||
|
||||
for m in managers:
|
||||
modname = m.__module__.split('.')[-2]
|
||||
gem_options.append(InputOption(label=i18n.get('gem.{}.label'.format(modname), modname.capitalize()),
|
||||
value=modname,
|
||||
icon_path='{r}/gems/{n}/resources/img/{n}.png'.format(r=ROOT_DIR, n=modname)))
|
||||
for m in manager.managers:
|
||||
if m.can_work():
|
||||
modname = m.__module__.split('.')[-2]
|
||||
gem_options.append(InputOption(label=i18n.get('gem.{}.label'.format(modname), modname.capitalize()),
|
||||
value=modname,
|
||||
icon_path='{r}/gems/{n}/resources/img/{n}.png'.format(r=ROOT_DIR, n=modname)))
|
||||
self.gem_map[modname] = m
|
||||
|
||||
if managers_set:
|
||||
default_ops = {o for o in gem_options if o.value in managers_set}
|
||||
if self.config.enabled_gems:
|
||||
default_ops = {o for o in gem_options if o.value in self.config.enabled_gems}
|
||||
else:
|
||||
default_ops = set(gem_options)
|
||||
|
||||
@@ -76,14 +72,19 @@ class GemSelectorPanel(QWidget):
|
||||
self.bt_proceed.setEnabled(bool(self.gem_select_model.values))
|
||||
|
||||
def save(self):
|
||||
config = Configuration(gems=[o.value for o in self.gem_select_model.values])
|
||||
save(config)
|
||||
enabled_gems = [op.value for op in self.gem_select_model.values]
|
||||
|
||||
util.restart_app(self.show_panel_after_restart)
|
||||
for module, man in self.gem_map.items():
|
||||
enabled = module in enabled_gems
|
||||
man.set_enabled(enabled)
|
||||
|
||||
self.config.enabled_gems = enabled_gems
|
||||
save(self.config)
|
||||
|
||||
self.manager.reset_cache()
|
||||
self.manager.prepare()
|
||||
self.window.refresh_apps()
|
||||
self.close()
|
||||
|
||||
def exit(self):
|
||||
if self.exit_on_close:
|
||||
QCoreApplication.exit()
|
||||
else:
|
||||
self.close()
|
||||
|
||||
self.close()
|
||||
|
||||
@@ -5,11 +5,10 @@ from typing import List
|
||||
from PyQt5.QtCore import QThread, pyqtSignal, QCoreApplication, Qt
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QSystemTrayIcon, QMenu
|
||||
from bauh.api.abstract.model import PackageUpdate
|
||||
|
||||
from bauh import __app_name__
|
||||
from bauh.api.abstract.controller import SoftwareManager
|
||||
from bauh.core.config import Configuration
|
||||
from bauh.api.abstract.model import PackageUpdate
|
||||
from bauh.util import util, resource
|
||||
from bauh.view.qt.about import AboutDialog
|
||||
from bauh.view.qt.window import ManageWindow
|
||||
@@ -34,11 +33,10 @@ class UpdateCheck(QThread):
|
||||
|
||||
class TrayIcon(QSystemTrayIcon):
|
||||
|
||||
def __init__(self, locale_keys: dict, manager: SoftwareManager, manage_window: ManageWindow, config: Configuration, check_interval: int = 60, update_notification: bool = True):
|
||||
def __init__(self, locale_keys: dict, manager: SoftwareManager, manage_window: ManageWindow, check_interval: int = 60, update_notification: bool = True):
|
||||
super(TrayIcon, self).__init__()
|
||||
self.locale_keys = locale_keys
|
||||
self.manager = manager
|
||||
self.config = config
|
||||
|
||||
self.icon_default = QIcon(resource.get_path('img/logo.png'))
|
||||
self.icon_update = QIcon(resource.get_path('img/logo_update.png'))
|
||||
@@ -118,12 +116,8 @@ class TrayIcon(QSystemTrayIcon):
|
||||
if self.manage_window.isMinimized():
|
||||
self.manage_window.setWindowState(Qt.WindowNoState)
|
||||
elif not self.manage_window.isVisible():
|
||||
if self.config.gems:
|
||||
self.manage_window.refresh_apps()
|
||||
self.manage_window.show()
|
||||
else:
|
||||
self.manage_window.show()
|
||||
self.manage_window.show_gems_selector()
|
||||
self.manage_window.refresh_apps()
|
||||
self.manage_window.show()
|
||||
|
||||
def show_about(self):
|
||||
|
||||
|
||||
@@ -213,10 +213,10 @@ class GetAppHistory(AsyncAction):
|
||||
self.app = None
|
||||
|
||||
|
||||
class SearchApps(AsyncAction):
|
||||
class SearchPackages(AsyncAction):
|
||||
|
||||
def __init__(self, manager: SoftwareManager):
|
||||
super(SearchApps, self).__init__()
|
||||
super(SearchPackages, self).__init__()
|
||||
self.word = None
|
||||
self.manager = manager
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ from typing import List, Type, Set
|
||||
|
||||
from PyQt5.QtCore import QEvent, Qt, QSize, pyqtSignal
|
||||
from PyQt5.QtGui import QIcon, QWindowStateChangeEvent, QPixmap, QCursor
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QCheckBox, QHeaderView, QToolBar, \
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QCheckBox, QHeaderView, QToolBar, \
|
||||
QLabel, QPlainTextEdit, QLineEdit, QProgressBar, QPushButton, QComboBox, QMenu, QAction
|
||||
|
||||
from bauh.api.abstract.cache import MemoryCache
|
||||
@@ -12,8 +12,8 @@ from bauh.api.abstract.context import ApplicationContext
|
||||
from bauh.api.abstract.controller import SoftwareManager
|
||||
from bauh.api.abstract.model import SoftwarePackage, PackageAction
|
||||
from bauh.api.abstract.view import MessageType
|
||||
from bauh.core import gems
|
||||
from bauh.core.config import Configuration
|
||||
from bauh.core.controller import GenericSoftwareManager
|
||||
from bauh.util import util, resource
|
||||
from bauh.view.qt import dialog, commons, qt_utils
|
||||
from bauh.view.qt.about import AboutDialog
|
||||
@@ -26,7 +26,7 @@ from bauh.view.qt.info import InfoDialog
|
||||
from bauh.view.qt.root import is_root, ask_root_password
|
||||
from bauh.view.qt.styles import StylesComboBox
|
||||
from bauh.view.qt.thread import UpdateSelectedApps, RefreshApps, UninstallApp, DowngradeApp, GetAppInfo, \
|
||||
GetAppHistory, SearchApps, InstallApp, AnimateProgress, VerifyModels, FindSuggestions, ListWarnings, \
|
||||
GetAppHistory, SearchPackages, InstallApp, AnimateProgress, VerifyModels, FindSuggestions, ListWarnings, \
|
||||
AsyncAction, RunApp, ApplyFilters, CustomAction
|
||||
from bauh.view.qt.view_model import PackageView
|
||||
from bauh.view.qt.view_utils import load_icon
|
||||
@@ -204,7 +204,7 @@ class ManageWindow(QWidget):
|
||||
self.thread_uninstall = self._bind_async_action(UninstallApp(self.manager, self.icon_cache), finished_call=self._finish_uninstall)
|
||||
self.thread_get_info = self._bind_async_action(GetAppInfo(self.manager), finished_call=self._finish_get_info)
|
||||
self.thread_get_history = self._bind_async_action(GetAppHistory(self.manager, self.i18n), finished_call=self._finish_get_history)
|
||||
self.thread_search = self._bind_async_action(SearchApps(self.manager), finished_call=self._finish_search, only_finished=True)
|
||||
self.thread_search = self._bind_async_action(SearchPackages(self.manager), finished_call=self._finish_search, only_finished=True)
|
||||
self.thread_downgrade = self._bind_async_action(DowngradeApp(self.manager, self.i18n), finished_call=self._finish_downgrade)
|
||||
self.thread_suggestions = self._bind_async_action(FindSuggestions(man=self.manager), finished_call=self._finish_search, only_finished=True)
|
||||
self.thread_run_app = self._bind_async_action(RunApp(), finished_call=self._finish_run_app, only_finished=False)
|
||||
@@ -900,21 +900,21 @@ class ManageWindow(QWidget):
|
||||
self.checkbox_console.setChecked(True)
|
||||
|
||||
def show_gems_selector(self):
|
||||
managers = gems.load_managers(context=self.context, locale=None)
|
||||
enabled_managers = [m for m in managers if m.is_enabled()]
|
||||
gem_panel = GemSelectorPanel(managers=enabled_managers, i18n=self.i18n,
|
||||
managers_set=self.config.gems,
|
||||
gem_panel = GemSelectorPanel(window=self,
|
||||
manager=self.manager, i18n=self.i18n,
|
||||
config=self.config,
|
||||
show_panel_after_restart=bool(self.tray_icon))
|
||||
gem_panel.show()
|
||||
|
||||
def _show_settings_menu(self):
|
||||
menu_row = QMenu()
|
||||
|
||||
action_gems = QAction(self.i18n['manage_window.settings.gems'])
|
||||
action_gems.setIcon(self.icon_app)
|
||||
if isinstance(self.manager, GenericSoftwareManager):
|
||||
action_gems = QAction(self.i18n['manage_window.settings.gems'])
|
||||
action_gems.setIcon(self.icon_app)
|
||||
|
||||
action_gems.triggered.connect(self.show_gems_selector)
|
||||
menu_row.addAction(action_gems)
|
||||
action_gems.triggered.connect(self.show_gems_selector)
|
||||
menu_row.addAction(action_gems)
|
||||
|
||||
action_about = QAction(self.i18n['manage_window.settings.about'])
|
||||
action_about.setIcon(QIcon(resource.get_path('img/about.svg')))
|
||||
|
||||
Reference in New Issue
Block a user