restart is not required when changing enabled gems

This commit is contained in:
Vinicius Moreira
2019-09-16 19:09:05 -03:00
parent 227e417491
commit c1410ca9b6
22 changed files with 183 additions and 127 deletions

View File

@@ -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

View File

@@ -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.

View File

@@ -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)

View File

@@ -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_())

View File

@@ -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):

View File

@@ -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:

View File

@@ -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

View File

@@ -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:

View File

@@ -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):

View File

@@ -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):

View File

@@ -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 ?

View File

@@ -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í?

View File

@@ -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 ?

View File

@@ -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))

View File

@@ -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']

View File

@@ -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
View File

@@ -0,0 +1,4 @@
OK_BUTTON = """QPushButton { background: green; color: white; font-weight: bold}
QPushButton:disabled { background-color: gray; }
"""

View File

@@ -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)

View File

@@ -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()

View File

@@ -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):

View File

@@ -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

View File

@@ -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')))