From c1410ca9b631d7ef7212047587d7330311416c61 Mon Sep 17 00:00:00 2001 From: Vinicius Moreira Date: Mon, 16 Sep 2019 19:09:05 -0300 Subject: [PATCH] restart is not required when changing enabled gems --- CHANGELOG.md | 17 ++++++++- bauh/api/abstract/controller.py | 16 +++++++- bauh/api/abstract/view.py | 2 +- bauh/app.py | 65 +++++++++++++------------------- bauh/core/config.py | 6 +-- bauh/core/controller.py | 38 ++++++++++++------- bauh/core/gems.py | 11 ++++-- bauh/gems/arch/controller.py | 10 ++++- bauh/gems/flatpak/controller.py | 7 ++++ bauh/gems/snap/controller.py | 7 ++++ bauh/resources/locale/en | 2 +- bauh/resources/locale/es | 2 +- bauh/resources/locale/pt | 2 +- bauh/view/qt/apps_table.py | 6 +-- bauh/view/qt/commons.py | 2 +- bauh/view/qt/confirmation.py | 2 + bauh/view/qt/css.py | 4 ++ bauh/view/qt/dialog.py | 2 + bauh/view/qt/gem_selector.py | 67 +++++++++++++++++---------------- bauh/view/qt/systray.py | 14 ++----- bauh/view/qt/thread.py | 4 +- bauh/view/qt/window.py | 24 ++++++------ 22 files changed, 183 insertions(+), 127 deletions(-) create mode 100644 bauh/view/qt/css.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 10951267..c8079252 100644 --- a/CHANGELOG.md +++ b/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 diff --git a/bauh/api/abstract/controller.py b/bauh/api/abstract/controller.py index 949bc876..47459b2f 100644 --- a/bauh/api/abstract/controller.py +++ b/bauh/api/abstract/controller.py @@ -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. diff --git a/bauh/api/abstract/view.py b/bauh/api/abstract/view.py index e6dbbb08..64136a4f 100644 --- a/bauh/api/abstract/view.py +++ b/bauh/api/abstract/view.py @@ -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) diff --git a/bauh/app.py b/bauh/app.py index ce0aac96..71c10475 100755 --- a/bauh/app.py +++ b/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_()) diff --git a/bauh/core/config.py b/bauh/core/config.py index d252009b..b58dd7cc 100644 --- a/bauh/core/config.py +++ b/bauh/core/config.py @@ -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): diff --git a/bauh/core/controller.py b/bauh/core/controller.py index e7aee17a..fb9bc656 100755 --- a/bauh/core/controller.py +++ b/bauh/core/controller.py @@ -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: diff --git a/bauh/core/gems.py b/bauh/core/gems.py index d5fa4599..57ebde44 100644 --- a/bauh/core/gems.py +++ b/bauh/core/gems.py @@ -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 diff --git a/bauh/gems/arch/controller.py b/bauh/gems/arch/controller.py index ec7464bf..02c2007d 100644 --- a/bauh/gems/arch/controller.py +++ b/bauh/gems/arch/controller.py @@ -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: diff --git a/bauh/gems/flatpak/controller.py b/bauh/gems/flatpak/controller.py index c6af0212..26021150 100644 --- a/bauh/gems/flatpak/controller.py +++ b/bauh/gems/flatpak/controller.py @@ -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): diff --git a/bauh/gems/snap/controller.py b/bauh/gems/snap/controller.py index a0049f0b..4107aaf4 100644 --- a/bauh/gems/snap/controller.py +++ b/bauh/gems/snap/controller.py @@ -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): diff --git a/bauh/resources/locale/en b/bauh/resources/locale/en index 94588f66..f7a43b92 100644 --- a/bauh/resources/locale/en +++ b/bauh/resources/locale/en @@ -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 ? diff --git a/bauh/resources/locale/es b/bauh/resources/locale/es index b98d253f..6855980a 100644 --- a/bauh/resources/locale/es +++ b/bauh/resources/locale/es @@ -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í? diff --git a/bauh/resources/locale/pt b/bauh/resources/locale/pt index fa80244d..361b1991 100644 --- a/bauh/resources/locale/pt +++ b/bauh/resources/locale/pt @@ -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 ? diff --git a/bauh/view/qt/apps_table.py b/bauh/view/qt/apps_table.py index e7f252fb..5101de95 100644 --- a/bauh/view/qt/apps_table.py +++ b/bauh/view/qt/apps_table.py @@ -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)) diff --git a/bauh/view/qt/commons.py b/bauh/view/qt/commons.py index c9767189..a78eaa1d 100644 --- a/bauh/view/qt/commons.py +++ b/bauh/view/qt/commons.py @@ -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'] diff --git a/bauh/view/qt/confirmation.py b/bauh/view/qt/confirmation.py index b0d13a51..53980ccb 100644 --- a/bauh/view/qt/confirmation.py +++ b/bauh/view/qt/confirmation.py @@ -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) diff --git a/bauh/view/qt/css.py b/bauh/view/qt/css.py new file mode 100644 index 00000000..8162b252 --- /dev/null +++ b/bauh/view/qt/css.py @@ -0,0 +1,4 @@ + +OK_BUTTON = """QPushButton { background: green; color: white; font-weight: bold} + QPushButton:disabled { background-color: gray; } + """ diff --git a/bauh/view/qt/dialog.py b/bauh/view/qt/dialog.py index 5e26c59a..31477d72 100644 --- a/bauh/view/qt/dialog.py +++ b/bauh/view/qt/dialog.py @@ -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) diff --git a/bauh/view/qt/gem_selector.py b/bauh/view/qt/gem_selector.py index e8ca9f80..e70efe6c 100644 --- a/bauh/view/qt/gem_selector.py +++ b/bauh/view/qt/gem_selector.py @@ -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() diff --git a/bauh/view/qt/systray.py b/bauh/view/qt/systray.py index 4b0559fb..3eea125c 100755 --- a/bauh/view/qt/systray.py +++ b/bauh/view/qt/systray.py @@ -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): diff --git a/bauh/view/qt/thread.py b/bauh/view/qt/thread.py index f76726ef..f96b9279 100644 --- a/bauh/view/qt/thread.py +++ b/bauh/view/qt/thread.py @@ -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 diff --git a/bauh/view/qt/window.py b/bauh/view/qt/window.py index dc4278c1..b17e9c92 100755 --- a/bauh/view/qt/window.py +++ b/bauh/view/qt/window.py @@ -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')))