mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-07 00:04:15 +02:00
[improvement][ui] big refactoring regarding the components states
This commit is contained in:
@@ -16,8 +16,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
- UI
|
- UI
|
||||||
- not performing a full table refresh after installing and uninstalling packages
|
- not performing a full table refresh after installing and uninstalling packages
|
||||||
- filters algorithm speed and sorting
|
- filters algorithm speed and sorting
|
||||||
- displaying wait cursor over some components
|
- "ignore updates" action now takes less time to update the table content
|
||||||
|
- displaying the "wait cursor" over some components while performing some actions
|
||||||
- sorting installed packages by their names
|
- sorting installed packages by their names
|
||||||
|
- big refactoring regarding the components states (now it is easier to maintain the code)
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
- AppImage
|
- AppImage
|
||||||
@@ -30,8 +32,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
- displaying empty categories
|
- displaying empty categories
|
||||||
- not scrolling the table to top after updating its content
|
- not scrolling the table to top after updating its content
|
||||||
- not calling initial required tasks after enabling a new package type on settings
|
- not calling initial required tasks after enabling a new package type on settings
|
||||||
- not updating the type filters if only type is available after refreshing the table
|
- not updating the type filters if only one type is available after refreshing the table
|
||||||
- displaying the type filters on the search results when there is only one type available and some actions are done
|
- displaying the type filters on the search results when there is only one type available after some actions finish
|
||||||
- minor fixes
|
- minor fixes
|
||||||
- Tray
|
- Tray
|
||||||
- update notifications not working on Ubuntu 18.04
|
- update notifications not working on Ubuntu 18.04
|
||||||
|
|||||||
@@ -623,7 +623,6 @@ class WebApplicationManager(SoftwareManager):
|
|||||||
continue_install, install_options = self._ask_install_options(pkg, watcher)
|
continue_install, install_options = self._ask_install_options(pkg, watcher)
|
||||||
|
|
||||||
if not continue_install:
|
if not continue_install:
|
||||||
watcher.print("Installation aborted by the user")
|
|
||||||
return TransactionResult(success=False, installed=[], removed=[])
|
return TransactionResult(success=False, installed=[], removed=[])
|
||||||
|
|
||||||
watcher.change_substatus(self.i18n['web.env.checking'])
|
watcher.change_substatus(self.i18n['web.env.checking'])
|
||||||
|
|||||||
@@ -21,11 +21,12 @@ class WebApplication(SoftwarePackage):
|
|||||||
self.source_url = source_url if source_url else url
|
self.source_url = source_url if source_url else url
|
||||||
self.installation_dir = installation_dir
|
self.installation_dir = installation_dir
|
||||||
self.desktop_entry = desktop_entry
|
self.desktop_entry = desktop_entry
|
||||||
self.set_custom_icon(custom_icon)
|
|
||||||
self.preset_options = preset_options
|
self.preset_options = preset_options
|
||||||
self.save_icon = save_icon # if the icon_url should be used instead of the one retrieved by nativefier
|
self.save_icon = save_icon # if the icon_url should be used instead of the one retrieved by nativefier
|
||||||
self.options_set = options_set
|
self.options_set = options_set
|
||||||
self.package_name = package_name
|
self.package_name = package_name
|
||||||
|
self.custom_icon = custom_icon
|
||||||
|
self.set_custom_icon(custom_icon)
|
||||||
|
|
||||||
def get_source_url(self):
|
def get_source_url(self):
|
||||||
if self.source_url:
|
if self.source_url:
|
||||||
|
|||||||
@@ -365,7 +365,12 @@ class GenericSoftwareManager(SoftwareManager):
|
|||||||
return history
|
return history
|
||||||
|
|
||||||
def get_managed_types(self) -> Set[Type[SoftwarePackage]]:
|
def get_managed_types(self) -> Set[Type[SoftwarePackage]]:
|
||||||
pass
|
available_types = set()
|
||||||
|
|
||||||
|
for man in self.get_working_managers():
|
||||||
|
available_types.update(man.get_managed_types())
|
||||||
|
|
||||||
|
return available_types
|
||||||
|
|
||||||
def is_enabled(self):
|
def is_enabled(self):
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ class AppsTable(QTableWidget):
|
|||||||
action_history.setIcon(QIcon(resource.get_path('img/history.svg')))
|
action_history.setIcon(QIcon(resource.get_path('img/history.svg')))
|
||||||
|
|
||||||
def show_history():
|
def show_history():
|
||||||
self.window.get_app_history(pkg)
|
self.window.begin_show_history(pkg)
|
||||||
|
|
||||||
action_history.triggered.connect(show_history)
|
action_history.triggered.connect(show_history)
|
||||||
menu_row.addAction(action_history)
|
menu_row.addAction(action_history)
|
||||||
@@ -141,7 +141,7 @@ class AppsTable(QTableWidget):
|
|||||||
title=self.i18n['manage_window.apps_table.row.actions.downgrade'],
|
title=self.i18n['manage_window.apps_table.row.actions.downgrade'],
|
||||||
body=self._parag(self.i18n['manage_window.apps_table.row.actions.downgrade.popup.body'].format(self._bold(str(pkg)))),
|
body=self._parag(self.i18n['manage_window.apps_table.row.actions.downgrade.popup.body'].format(self._bold(str(pkg)))),
|
||||||
i18n=self.i18n):
|
i18n=self.i18n):
|
||||||
self.window.downgrade(pkg)
|
self.window.begin_downgrade(pkg)
|
||||||
|
|
||||||
action_downgrade.triggered.connect(downgrade)
|
action_downgrade.triggered.connect(downgrade)
|
||||||
action_downgrade.setIcon(QIcon(resource.get_path('img/downgrade.svg')))
|
action_downgrade.setIcon(QIcon(resource.get_path('img/downgrade.svg')))
|
||||||
@@ -157,7 +157,7 @@ class AppsTable(QTableWidget):
|
|||||||
action_ignore_updates.setIcon(QIcon(resource.get_path('img/ignore_update.svg')))
|
action_ignore_updates.setIcon(QIcon(resource.get_path('img/ignore_update.svg')))
|
||||||
|
|
||||||
def ignore_updates():
|
def ignore_updates():
|
||||||
self.window.ignore_updates(pkg)
|
self.window.begin_ignore_updates(pkg)
|
||||||
|
|
||||||
action_ignore_updates.triggered.connect(ignore_updates)
|
action_ignore_updates.triggered.connect(ignore_updates)
|
||||||
menu_row.addAction(action_ignore_updates)
|
menu_row.addAction(action_ignore_updates)
|
||||||
@@ -174,7 +174,7 @@ class AppsTable(QTableWidget):
|
|||||||
title=self.i18n[action.i18_label_key],
|
title=self.i18n[action.i18_label_key],
|
||||||
body=self._parag('{} {} ?'.format(self.i18n[action.i18_label_key], self._bold(str(pkg)))),
|
body=self._parag('{} {} ?'.format(self.i18n[action.i18_label_key], self._bold(str(pkg)))),
|
||||||
i18n=self.i18n):
|
i18n=self.i18n):
|
||||||
self.window.execute_custom_action(pkg, action)
|
self.window.begin_execute_custom_action(pkg, action)
|
||||||
|
|
||||||
item.triggered.connect(custom_action)
|
item.triggered.connect(custom_action)
|
||||||
menu_row.addAction(item)
|
menu_row.addAction(item)
|
||||||
@@ -198,7 +198,7 @@ class AppsTable(QTableWidget):
|
|||||||
if dialog.ask_confirmation(title=self.i18n['manage_window.apps_table.row.actions.uninstall.popup.title'],
|
if dialog.ask_confirmation(title=self.i18n['manage_window.apps_table.row.actions.uninstall.popup.title'],
|
||||||
body=self._parag(self.i18n['manage_window.apps_table.row.actions.uninstall.popup.body'].format(self._bold(str(pkg)))),
|
body=self._parag(self.i18n['manage_window.apps_table.row.actions.uninstall.popup.body'].format(self._bold(str(pkg)))),
|
||||||
i18n=self.i18n):
|
i18n=self.i18n):
|
||||||
self.window.uninstall_package(pkg)
|
self.window.begin_uninstall(pkg)
|
||||||
|
|
||||||
def _bold(self, text: str) -> str:
|
def _bold(self, text: str) -> str:
|
||||||
return '<span style="font-weight: bold">{}</span>'.format(text)
|
return '<span style="font-weight: bold">{}</span>'.format(text)
|
||||||
@@ -495,7 +495,7 @@ class AppsTable(QTableWidget):
|
|||||||
|
|
||||||
if pkg.model.installed:
|
if pkg.model.installed:
|
||||||
def run():
|
def run():
|
||||||
self.window.run_app(pkg)
|
self.window.begin_launch_package(pkg)
|
||||||
|
|
||||||
bt = IconButton(QIcon(resource.get_path('img/app_play.svg')), i18n=self.i18n, action=run, tooltip=self.i18n['action.run.tooltip'])
|
bt = IconButton(QIcon(resource.get_path('img/app_play.svg')), i18n=self.i18n, action=run, tooltip=self.i18n['action.run.tooltip'])
|
||||||
bt.setEnabled(pkg.model.can_be_run())
|
bt.setEnabled(pkg.model.can_be_run())
|
||||||
@@ -511,18 +511,18 @@ class AppsTable(QTableWidget):
|
|||||||
item.addWidget(bt)
|
item.addWidget(bt)
|
||||||
|
|
||||||
if not pkg.model.installed:
|
if not pkg.model.installed:
|
||||||
def get_screenshots():
|
def show_screenshots():
|
||||||
self.window.get_screenshots(pkg)
|
self.window.begin_show_screenshots(pkg)
|
||||||
|
|
||||||
bt = IconButton(QIcon(resource.get_path('img/camera.svg')), i18n=self.i18n, action=get_screenshots,
|
bt = IconButton(QIcon(resource.get_path('img/camera.svg')), i18n=self.i18n, action=show_screenshots,
|
||||||
tooltip=self.i18n['action.screenshots.tooltip'])
|
tooltip=self.i18n['action.screenshots.tooltip'])
|
||||||
bt.setEnabled(bool(pkg.model.has_screenshots()))
|
bt.setEnabled(bool(pkg.model.has_screenshots()))
|
||||||
item.addWidget(bt)
|
item.addWidget(bt)
|
||||||
|
|
||||||
def get_info():
|
def show_info():
|
||||||
self.window.get_app_info(pkg)
|
self.window.begin_show_info(pkg)
|
||||||
|
|
||||||
bt = IconButton(QIcon(resource.get_path('img/app_info.svg')), i18n=self.i18n, action=get_info, tooltip=self.i18n['action.info.tooltip'])
|
bt = IconButton(QIcon(resource.get_path('img/app_info.svg')), i18n=self.i18n, action=show_info, tooltip=self.i18n['action.info.tooltip'])
|
||||||
bt.setEnabled(bool(pkg.model.has_info()))
|
bt.setEnabled(bool(pkg.model.has_info()))
|
||||||
item.addWidget(bt)
|
item.addWidget(bt)
|
||||||
|
|
||||||
|
|||||||
@@ -41,21 +41,25 @@ def update_info(pkgv: PackageView, pkgs_info: dict):
|
|||||||
pkgs_info['not_installed'] += 1 if not pkgv.model.installed else 0
|
pkgs_info['not_installed'] += 1 if not pkgv.model.installed else 0
|
||||||
|
|
||||||
|
|
||||||
def apply_filters(pkgv: PackageView, filters: dict, info: dict, limit: bool = True):
|
def apply_filters(pkg: PackageView, filters: dict, info: dict, limit: bool = True):
|
||||||
if not limit or not filters['display_limit'] or len(info['pkgs_displayed']) < filters['display_limit']:
|
if not limit or not filters['display_limit'] or len(info['pkgs_displayed']) < filters['display_limit']:
|
||||||
hidden = filters['only_apps'] and pkgv.model.installed and not pkgv.model.is_application()
|
if not is_package_hidden(pkg, filters):
|
||||||
|
info['pkgs_displayed'].append(pkg)
|
||||||
|
|
||||||
if not hidden and filters['updates']:
|
|
||||||
hidden = not pkgv.model.update or pkgv.model.is_update_ignored()
|
|
||||||
|
|
||||||
if not hidden and filters['type'] is not None and filters['type'] != 'any':
|
def is_package_hidden(pkg: PackageView, filters: dict) -> bool:
|
||||||
hidden = pkgv.model.get_type() != filters['type']
|
hidden = filters['only_apps'] and pkg.model.installed and not pkg.model.is_application()
|
||||||
|
|
||||||
if not hidden and filters['category'] is not None and filters['category'] != 'any':
|
if not hidden and filters['updates']:
|
||||||
hidden = not pkgv.model.categories or not [c for c in pkgv.model.categories if c.lower() == filters['category']]
|
hidden = not pkg.model.update or pkg.model.is_update_ignored()
|
||||||
|
|
||||||
if not hidden and filters['name']:
|
if not hidden and filters['type'] is not None and filters['type'] != 'any':
|
||||||
hidden = not filters['name'] in pkgv.model.name.lower()
|
hidden = pkg.model.get_type() != filters['type']
|
||||||
|
|
||||||
if not hidden:
|
if not hidden and filters['category'] is not None and filters['category'] != 'any':
|
||||||
info['pkgs_displayed'].append(pkgv)
|
hidden = not pkg.model.categories or not [c for c in pkg.model.categories if c.lower() == filters['category']]
|
||||||
|
|
||||||
|
if not hidden and filters['name']:
|
||||||
|
hidden = not filters['name'] in pkg.model.name.lower()
|
||||||
|
|
||||||
|
return hidden
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import time
|
|||||||
import traceback
|
import traceback
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from typing import Tuple
|
from typing import Tuple, Dict, Optional, Set
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt, QSize
|
from PyQt5.QtCore import Qt, QSize
|
||||||
from PyQt5.QtGui import QIcon, QPixmap, QIntValidator, QCursor
|
from PyQt5.QtGui import QIcon, QPixmap, QIntValidator, QCursor
|
||||||
from PyQt5.QtWidgets import QRadioButton, QGroupBox, QCheckBox, QComboBox, QGridLayout, QWidget, \
|
from PyQt5.QtWidgets import QRadioButton, QGroupBox, QCheckBox, QComboBox, QGridLayout, QWidget, \
|
||||||
QLabel, QSizePolicy, QLineEdit, QToolButton, QHBoxLayout, QFormLayout, QFileDialog, QTabWidget, QVBoxLayout, \
|
QLabel, QSizePolicy, QLineEdit, QToolButton, QHBoxLayout, QFormLayout, QFileDialog, QTabWidget, QVBoxLayout, \
|
||||||
QSlider, QScrollArea, QFrame
|
QSlider, QScrollArea, QFrame, QAction
|
||||||
|
|
||||||
from bauh.api.abstract.view import SingleSelectComponent, InputOption, MultipleSelectComponent, SelectViewType, \
|
from bauh.api.abstract.view import SingleSelectComponent, InputOption, MultipleSelectComponent, SelectViewType, \
|
||||||
TextInputComponent, FormComponent, FileChooserComponent, ViewComponent, TabGroupComponent, PanelComponent, \
|
TextInputComponent, FormComponent, FileChooserComponent, ViewComponent, TabGroupComponent, PanelComponent, \
|
||||||
@@ -20,6 +20,247 @@ from bauh.view.util import resource
|
|||||||
from bauh.view.util.translation import I18n
|
from bauh.view.util.translation import I18n
|
||||||
|
|
||||||
|
|
||||||
|
class QtComponentsManager:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.components = {}
|
||||||
|
self.groups = {}
|
||||||
|
self.group_of_groups = {}
|
||||||
|
self._saved_states = {}
|
||||||
|
|
||||||
|
def register_component(self, component_id: int, instance: QWidget, action: QAction = None):
|
||||||
|
comp = (instance, action, {'v': True, 'e': True, 'r': False})
|
||||||
|
self.components[component_id] = comp
|
||||||
|
self._save_state(comp)
|
||||||
|
|
||||||
|
def register_group(self, group_id: int, subgroups: bool, *ids: int):
|
||||||
|
if not subgroups:
|
||||||
|
self.groups[group_id] = {*ids}
|
||||||
|
else:
|
||||||
|
self.group_of_groups[group_id] = {*ids}
|
||||||
|
|
||||||
|
def get_subgroups(self, root_group: int) -> Set[str]:
|
||||||
|
return self.group_of_groups.get(root_group, set())
|
||||||
|
|
||||||
|
def set_components_visible(self, visible: bool, *ids: int):
|
||||||
|
if ids:
|
||||||
|
for cid in ids:
|
||||||
|
self.set_component_visible(cid, visible)
|
||||||
|
else:
|
||||||
|
for cid in self.components:
|
||||||
|
self.set_component_visible(cid, visible)
|
||||||
|
|
||||||
|
def set_component_visible(self, cid: int, visible: bool):
|
||||||
|
comp = self.components.get(cid)
|
||||||
|
if comp and self._is_visible(comp) != visible:
|
||||||
|
self._save_state(comp)
|
||||||
|
self._set_visible(comp, visible)
|
||||||
|
|
||||||
|
def set_component_enabled(self, cid: int, enabled: bool):
|
||||||
|
comp = self.components.get(cid)
|
||||||
|
if comp and self._is_enabled(comp) != enabled:
|
||||||
|
self._save_state(comp)
|
||||||
|
self._set_enabled(comp, enabled)
|
||||||
|
|
||||||
|
def set_component_read_only(self, cid: int, read_only: bool):
|
||||||
|
comp = self.components.get(cid)
|
||||||
|
if comp and self._supports_read_only(comp) and self._is_read_only(comp) != read_only:
|
||||||
|
self._save_state(comp)
|
||||||
|
self._set_read_only(comp, read_only)
|
||||||
|
|
||||||
|
def set_components_enabled(self, enabled: bool, *ids: int):
|
||||||
|
if ids:
|
||||||
|
for cid in ids:
|
||||||
|
self.set_component_enabled(cid, enabled)
|
||||||
|
else:
|
||||||
|
for cid in self.components:
|
||||||
|
self.set_component_enabled(cid, enabled)
|
||||||
|
|
||||||
|
def restore_previous_states(self, *ids: int):
|
||||||
|
if ids:
|
||||||
|
for cid in ids:
|
||||||
|
self.restore_previous_state(cid)
|
||||||
|
else:
|
||||||
|
for cid in self.components:
|
||||||
|
self.restore_previous_state(cid)
|
||||||
|
|
||||||
|
def restore_previous_group_state(self, group_id: int):
|
||||||
|
ids = self.groups.get(group_id)
|
||||||
|
|
||||||
|
if ids:
|
||||||
|
self.restore_previous_states(*ids)
|
||||||
|
|
||||||
|
def restore_previous_groups_states(self, *groups: int):
|
||||||
|
if groups:
|
||||||
|
for group in groups:
|
||||||
|
self.restore_previous_group_state(group)
|
||||||
|
|
||||||
|
def set_group_visible(self, group_id: int, visible: bool):
|
||||||
|
ids = self.groups.get(group_id)
|
||||||
|
|
||||||
|
if ids:
|
||||||
|
self.set_components_visible(visible, *ids)
|
||||||
|
|
||||||
|
def set_groups_visible(self, visible: bool, *groups: int):
|
||||||
|
if groups:
|
||||||
|
for group in groups:
|
||||||
|
self.set_group_visible(group, visible)
|
||||||
|
|
||||||
|
def set_group_enabled(self, group_id: int, enabled: bool):
|
||||||
|
ids = self.groups.get(group_id)
|
||||||
|
|
||||||
|
if ids:
|
||||||
|
self.set_components_enabled(enabled, *ids)
|
||||||
|
|
||||||
|
def restore_previous_state(self, cid: int):
|
||||||
|
comp = self.components.get(cid)
|
||||||
|
|
||||||
|
if comp:
|
||||||
|
previous_state = {**comp[2]}
|
||||||
|
self._restore_state(comp, previous_state)
|
||||||
|
|
||||||
|
def _set_visible(self, comp: Tuple[QWidget, Optional[QAction], Dict[str, bool]], visible: bool):
|
||||||
|
if comp[1]:
|
||||||
|
comp[1].setVisible(visible)
|
||||||
|
else:
|
||||||
|
comp[0].setVisible(visible)
|
||||||
|
|
||||||
|
def _set_enabled(self, comp: Tuple[QWidget, Optional[QAction], Dict[str, bool]], enabled: bool):
|
||||||
|
comp[0].setEnabled(enabled)
|
||||||
|
|
||||||
|
def _set_read_only(self, comp: Tuple[QWidget, Optional[QAction], Dict[str, bool]], read_only: bool):
|
||||||
|
comp[0].setReadOnly(read_only)
|
||||||
|
|
||||||
|
def _supports_read_only(self, comp: Tuple[QWidget, Optional[QAction], Dict[str, bool]]) -> bool:
|
||||||
|
return isinstance(comp, QLineEdit)
|
||||||
|
|
||||||
|
def is_visible(self, cid: int) -> bool:
|
||||||
|
comp = self.components.get(cid)
|
||||||
|
return self._is_visible(comp) if comp else False
|
||||||
|
|
||||||
|
def _is_visible(self, comp: Tuple[QWidget, Optional[QAction], Dict[str, bool]]) -> bool:
|
||||||
|
return comp[1].isVisible() if comp[1] else comp[0].isVisible()
|
||||||
|
|
||||||
|
def _is_enabled(self, comp: Tuple[QWidget, Optional[QAction], Dict[str, bool]]) -> bool:
|
||||||
|
return comp[0].isEnabled()
|
||||||
|
|
||||||
|
def _is_read_only(self, comp: Tuple[QWidget, Optional[QAction], Dict[str, bool]]) -> bool:
|
||||||
|
return comp[0].isReadOnly() if self._supports_read_only(comp) else False
|
||||||
|
|
||||||
|
def _save_state(self, comp: Tuple[QWidget, Optional[QAction], Dict[str, bool]]):
|
||||||
|
comp[2]['v'] = self._is_visible(comp)
|
||||||
|
comp[2]['e'] = self._is_enabled(comp)
|
||||||
|
comp[2]['r'] = self._is_read_only(comp)
|
||||||
|
|
||||||
|
def list_visible_from_group(self, group_id: int) -> Set[str]:
|
||||||
|
ids = self.groups.get(group_id)
|
||||||
|
if ids:
|
||||||
|
return {cid for cid in ids if self.is_visible(cid)}
|
||||||
|
|
||||||
|
def disable_visible_from_groups(self, *groups):
|
||||||
|
if groups:
|
||||||
|
for group in groups:
|
||||||
|
ids = self.list_visible_from_group(group)
|
||||||
|
|
||||||
|
if ids:
|
||||||
|
self.set_components_enabled(False, *ids)
|
||||||
|
|
||||||
|
def disable_visible(self):
|
||||||
|
self.set_components_enabled(False, *{cid for cid in self.components if self.is_visible(cid)})
|
||||||
|
|
||||||
|
def enable_visible(self):
|
||||||
|
self.set_components_enabled(True, *{cid for cid in self.components if self.is_visible(cid)})
|
||||||
|
|
||||||
|
def enable_visible_from_groups(self, *groups):
|
||||||
|
if groups:
|
||||||
|
for group in groups:
|
||||||
|
ids = self.list_visible_from_group(group)
|
||||||
|
|
||||||
|
if ids:
|
||||||
|
self.set_components_enabled(True, *ids)
|
||||||
|
|
||||||
|
def save_state(self, cid: int, state_id: int):
|
||||||
|
comp = self.components.get(cid)
|
||||||
|
|
||||||
|
if comp:
|
||||||
|
self._save_state(comp)
|
||||||
|
states = self._saved_states.get(state_id)
|
||||||
|
|
||||||
|
if states is None:
|
||||||
|
states = {}
|
||||||
|
self._saved_states[state_id] = states
|
||||||
|
|
||||||
|
states[cid] = {**comp[2]}
|
||||||
|
|
||||||
|
def save_states(self, state_id: int, *ids, only_visible: bool = False):
|
||||||
|
for cid in (ids if ids else self.components):
|
||||||
|
if not only_visible or self.is_visible(cid):
|
||||||
|
self.save_state(cid, state_id)
|
||||||
|
|
||||||
|
def save_group_state(self, group_id: int, state_id: int):
|
||||||
|
ids = self.groups.get(group_id)
|
||||||
|
|
||||||
|
if ids:
|
||||||
|
self.save_states(state_id, *ids)
|
||||||
|
|
||||||
|
def save_groups_states(self, state_id: int, *group_ids):
|
||||||
|
if group_ids:
|
||||||
|
for group_id in group_ids:
|
||||||
|
self.save_group_state(group_id, state_id)
|
||||||
|
|
||||||
|
def _restore_state(self, comp: Tuple[QWidget, Optional[QAction], Dict[str, bool]], state: Dict[str, bool]):
|
||||||
|
self._save_state(comp)
|
||||||
|
|
||||||
|
if state['v'] != self._is_visible(comp):
|
||||||
|
self._set_visible(comp, state['v'])
|
||||||
|
|
||||||
|
if state['e'] != self._is_enabled(comp):
|
||||||
|
self._set_enabled(comp, state['e'])
|
||||||
|
|
||||||
|
if state['r'] != self._is_read_only(comp):
|
||||||
|
self._set_read_only(comp, state['r'])
|
||||||
|
|
||||||
|
def restore_group_state(self, group_id: int, state_id: int):
|
||||||
|
states = self._saved_states.get(state_id)
|
||||||
|
|
||||||
|
if states:
|
||||||
|
ids = self.groups.get(group_id)
|
||||||
|
|
||||||
|
if ids:
|
||||||
|
for cid in ids:
|
||||||
|
comp_state = states.get(cid)
|
||||||
|
|
||||||
|
if comp_state:
|
||||||
|
comp = self.components.get(cid)
|
||||||
|
|
||||||
|
if comp:
|
||||||
|
self._restore_state(comp, comp_state)
|
||||||
|
|
||||||
|
def restore_groups_state(self, state_id: int, *group_ids):
|
||||||
|
if group_ids:
|
||||||
|
for group_id in group_ids:
|
||||||
|
self.restore_group_state(group_id, state_id)
|
||||||
|
|
||||||
|
def restore_state(self, state_id: int):
|
||||||
|
state = self._saved_states.get(state_id)
|
||||||
|
|
||||||
|
if state:
|
||||||
|
for cid, cstate in state.items():
|
||||||
|
comp = self.components.get(cid)
|
||||||
|
|
||||||
|
if comp:
|
||||||
|
self._restore_state(comp, cstate)
|
||||||
|
|
||||||
|
del self._saved_states[state_id]
|
||||||
|
|
||||||
|
def clear_saved_states(self):
|
||||||
|
self._saved_states.clear()
|
||||||
|
|
||||||
|
def remove_saved_state(self, state_id: int):
|
||||||
|
if state_id in self._saved_states:
|
||||||
|
del self._saved_states[state_id]
|
||||||
|
|
||||||
|
|
||||||
class RadioButtonQt(QRadioButton):
|
class RadioButtonQt(QRadioButton):
|
||||||
|
|
||||||
def __init__(self, model: InputOption, model_parent: SingleSelectComponent):
|
def __init__(self, model: InputOption, model_parent: SingleSelectComponent):
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ class GemSelectorPanel(QWidget):
|
|||||||
self.manager.prepare()
|
self.manager.prepare()
|
||||||
self.window.verify_warnings()
|
self.window.verify_warnings()
|
||||||
self.window.types_changed = True
|
self.window.types_changed = True
|
||||||
self.window.refresh_packages()
|
self.window.begin_refresh_packages()
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def exit(self):
|
def exit(self):
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ IGNORED_ATTRS = {'name', '__app__'}
|
|||||||
|
|
||||||
class InfoDialog(QDialog):
|
class InfoDialog(QDialog):
|
||||||
|
|
||||||
def __init__(self, app: dict, icon_cache: MemoryCache, i18n: I18n, screen_size: QSize):
|
def __init__(self, pkg_info: dict, icon_cache: MemoryCache, i18n: I18n, screen_size: QSize):
|
||||||
super(InfoDialog, self).__init__(flags=Qt.CustomizeWindowHint | Qt.WindowTitleHint)
|
super(InfoDialog, self).__init__(flags=Qt.CustomizeWindowHint | Qt.WindowTitleHint)
|
||||||
self.setWindowTitle(str(app['__app__']))
|
self.setWindowTitle(str(pkg_info['__app__']))
|
||||||
self.screen_size = screen_size
|
self.screen_size = screen_size
|
||||||
self.i18n = i18n
|
self.i18n = i18n
|
||||||
layout = QVBoxLayout()
|
layout = QVBoxLayout()
|
||||||
@@ -44,17 +44,17 @@ class InfoDialog(QDialog):
|
|||||||
#
|
#
|
||||||
# if icon_data and icon_data.get('icon'):
|
# if icon_data and icon_data.get('icon'):
|
||||||
# self.setWindowIcon(icon_data.get('icon'))
|
# self.setWindowIcon(icon_data.get('icon'))
|
||||||
self.setWindowIcon(QIcon(app['__app__'].model.get_type_icon_path()))
|
self.setWindowIcon(QIcon(pkg_info['__app__'].model.get_type_icon_path()))
|
||||||
|
|
||||||
for idx, attr in enumerate(sorted(app.keys())):
|
for idx, attr in enumerate(sorted(pkg_info.keys())):
|
||||||
if attr not in IGNORED_ATTRS and app[attr]:
|
if attr not in IGNORED_ATTRS and pkg_info[attr]:
|
||||||
i18n_key = app['__app__'].model.gem_name + '.info.' + attr.lower()
|
i18n_key = pkg_info['__app__'].model.gem_name + '.info.' + attr.lower()
|
||||||
|
|
||||||
if isinstance(app[attr], list):
|
if isinstance(pkg_info[attr], list):
|
||||||
val = ' '.join([str(e).strip() for e in app[attr] if e])
|
val = ' '.join([str(e).strip() for e in pkg_info[attr] if e])
|
||||||
show_val = '\n'.join(['* ' + str(e).strip() for e in app[attr] if e])
|
show_val = '\n'.join(['* ' + str(e).strip() for e in pkg_info[attr] if e])
|
||||||
else:
|
else:
|
||||||
val = str(app[attr]).strip()
|
val = str(pkg_info[attr]).strip()
|
||||||
show_val = val
|
show_val = val
|
||||||
|
|
||||||
i18n_val = i18n.get('{}.{}'.format(i18n_key, val.lower()))
|
i18n_val = i18n.get('{}.{}'.format(i18n_key, val.lower()))
|
||||||
@@ -90,7 +90,7 @@ class InfoDialog(QDialog):
|
|||||||
|
|
||||||
bt_close = QPushButton(self.i18n['close'].capitalize())
|
bt_close = QPushButton(self.i18n['close'].capitalize())
|
||||||
bt_close.setCursor(QCursor(Qt.PointingHandCursor))
|
bt_close.setCursor(QCursor(Qt.PointingHandCursor))
|
||||||
bt_close.clicked.connect(lambda: self.close())
|
bt_close.clicked.connect(self.close)
|
||||||
|
|
||||||
lower_bar.addWidget(bt_close)
|
lower_bar.addWidget(bt_close)
|
||||||
layout.addWidget(lower_bar)
|
layout.addWidget(lower_bar)
|
||||||
|
|||||||
@@ -393,7 +393,7 @@ class PreparePanel(QWidget, TaskManager):
|
|||||||
|
|
||||||
def finish(self):
|
def finish(self):
|
||||||
if self.isVisible():
|
if self.isVisible():
|
||||||
self.manage_window.refresh_packages()
|
self.manage_window.begin_refresh_packages()
|
||||||
self.manage_window.show()
|
self.manage_window.show()
|
||||||
self.self_close = True
|
self.self_close = True
|
||||||
self.close()
|
self.close()
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
from PyQt5.QtGui import QIcon, QPixmap
|
||||||
from PyQt5.QtWidgets import QWidget, QApplication
|
from PyQt5.QtWidgets import QWidget, QApplication
|
||||||
|
|
||||||
|
from bauh.view.util import resource
|
||||||
|
|
||||||
|
|
||||||
def centralize(widget: QWidget):
|
def centralize(widget: QWidget):
|
||||||
geo = widget.frameGeometry()
|
geo = widget.frameGeometry()
|
||||||
@@ -7,3 +11,11 @@ def centralize(widget: QWidget):
|
|||||||
center_point = QApplication.desktop().screenGeometry(screen).center()
|
center_point = QApplication.desktop().screenGeometry(screen).center()
|
||||||
geo.moveCenter(center_point)
|
geo.moveCenter(center_point)
|
||||||
widget.move(geo.topLeft())
|
widget.move(geo.topLeft())
|
||||||
|
|
||||||
|
|
||||||
|
def load_icon(path: str, width: int, height: int = None) -> QIcon:
|
||||||
|
return QIcon(QPixmap(path).scaled(width, height if height else width, Qt.KeepAspectRatio, Qt.SmoothTransformation))
|
||||||
|
|
||||||
|
|
||||||
|
def load_resource_icon(path: str, width: int, height: int = None) -> QIcon:
|
||||||
|
return load_icon(resource.get_path(path), width, height)
|
||||||
|
|||||||
@@ -3,23 +3,28 @@ from typing import Tuple
|
|||||||
|
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
from PyQt5.QtGui import QCursor, QIcon
|
from PyQt5.QtGui import QCursor, QIcon
|
||||||
from PyQt5.QtWidgets import QInputDialog, QLineEdit, QDialogButtonBox
|
from PyQt5.QtWidgets import QInputDialog, QLineEdit, QDialogButtonBox, QApplication
|
||||||
|
|
||||||
from bauh.api.abstract.context import ApplicationContext
|
from bauh.api.abstract.context import ApplicationContext
|
||||||
from bauh.api.abstract.view import MessageType
|
from bauh.api.abstract.view import MessageType
|
||||||
from bauh.commons.system import new_subprocess
|
from bauh.commons.system import new_subprocess
|
||||||
from bauh.view.core.config import read_config
|
from bauh.view.core.config import read_config
|
||||||
from bauh.view.qt import css
|
from bauh.view.qt import css
|
||||||
|
from bauh.view.qt.components import QtComponentsManager
|
||||||
from bauh.view.qt.dialog import show_message
|
from bauh.view.qt.dialog import show_message
|
||||||
from bauh.view.util import util
|
from bauh.view.util import util
|
||||||
from bauh.view.util.translation import I18n
|
from bauh.view.util.translation import I18n
|
||||||
|
|
||||||
|
ACTION_ASK_ROOT = 99
|
||||||
|
|
||||||
|
|
||||||
def is_root():
|
def is_root():
|
||||||
return os.getuid() == 0
|
return os.getuid() == 0
|
||||||
|
|
||||||
|
|
||||||
def ask_root_password(context: ApplicationContext, i18n: I18n, app_config: dict = None) -> Tuple[str, bool]:
|
def ask_root_password(context: ApplicationContext, i18n: I18n,
|
||||||
|
app_config: dict = None,
|
||||||
|
comp_manager: QtComponentsManager = None) -> Tuple[str, bool]:
|
||||||
|
|
||||||
cur_config = read_config() if not app_config else app_config
|
cur_config = read_config() if not app_config else app_config
|
||||||
store_password = bool(cur_config['store_root_password'])
|
store_password = bool(cur_config['store_root_password'])
|
||||||
@@ -48,13 +53,20 @@ def ask_root_password(context: ApplicationContext, i18n: I18n, app_config: dict
|
|||||||
|
|
||||||
diag.resize(400, 200)
|
diag.resize(400, 200)
|
||||||
|
|
||||||
|
if comp_manager:
|
||||||
|
comp_manager.save_states(state_id=ACTION_ASK_ROOT, only_visible=True)
|
||||||
|
comp_manager.disable_visible()
|
||||||
|
|
||||||
for attempt in range(3):
|
for attempt in range(3):
|
||||||
|
|
||||||
ok = diag.exec_()
|
ok = diag.exec_()
|
||||||
|
|
||||||
if ok:
|
if ok:
|
||||||
if not validate_password(diag.textValue()):
|
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||||
|
valid = validate_password(diag.textValue())
|
||||||
|
QApplication.restoreOverrideCursor()
|
||||||
|
|
||||||
|
if not valid:
|
||||||
body = i18n['popup.root.bad_password.body']
|
body = i18n['popup.root.bad_password.body']
|
||||||
|
|
||||||
if attempt == 2:
|
if attempt == 2:
|
||||||
@@ -70,10 +82,16 @@ def ask_root_password(context: ApplicationContext, i18n: I18n, app_config: dict
|
|||||||
if store_password:
|
if store_password:
|
||||||
context.root_password = diag.textValue()
|
context.root_password = diag.textValue()
|
||||||
|
|
||||||
|
if comp_manager:
|
||||||
|
comp_manager.restore_state(ACTION_ASK_ROOT)
|
||||||
|
|
||||||
return diag.textValue(), ok
|
return diag.textValue(), ok
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if comp_manager:
|
||||||
|
comp_manager.restore_state(ACTION_ASK_ROOT)
|
||||||
|
|
||||||
return '', False
|
return '', False
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from bauh.view.util.translation import I18n
|
|||||||
class SettingsWindow(QWidget):
|
class SettingsWindow(QWidget):
|
||||||
|
|
||||||
def __init__(self, manager: SoftwareManager, i18n: I18n, screen_size: QSize, window: QWidget, parent: QWidget = None):
|
def __init__(self, manager: SoftwareManager, i18n: I18n, screen_size: QSize, window: QWidget, parent: QWidget = None):
|
||||||
super(SettingsWindow, self).__init__(parent=parent)
|
super(SettingsWindow, self).__init__(parent=parent, flags=Qt.CustomizeWindowHint | Qt.WindowTitleHint)
|
||||||
self.setWindowTitle('{} ({})'.format(i18n['settings'].capitalize(), __app_name__))
|
self.setWindowTitle('{} ({})'.format(i18n['settings'].capitalize(), __app_name__))
|
||||||
self.setLayout(QVBoxLayout())
|
self.setLayout(QVBoxLayout())
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
@@ -96,7 +96,7 @@ class SettingsWindow(QWidget):
|
|||||||
self.window.update_custom_actions()
|
self.window.update_custom_actions()
|
||||||
self.window.verify_warnings()
|
self.window.verify_warnings()
|
||||||
self.window.types_changed = True
|
self.window.types_changed = True
|
||||||
self.window.refresh_packages()
|
self.window.begin_refresh_packages()
|
||||||
self.close()
|
self.close()
|
||||||
else:
|
else:
|
||||||
msg = StringIO()
|
msg = StringIO()
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from bauh.context import generate_i18n
|
|||||||
from bauh.view.core.tray_client import TRAY_CHECK_FILE
|
from bauh.view.core.tray_client import TRAY_CHECK_FILE
|
||||||
from bauh.view.core.update import check_for_update
|
from bauh.view.core.update import check_for_update
|
||||||
from bauh.view.qt.about import AboutDialog
|
from bauh.view.qt.about import AboutDialog
|
||||||
from bauh.view.qt.view_utils import load_resource_icon
|
from bauh.view.qt.qt_utils import load_resource_icon
|
||||||
from bauh.view.util import util, resource
|
from bauh.view.util import util, resource
|
||||||
from bauh.view.util.translation import I18n
|
from bauh.view.util.translation import I18n
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import requests
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
from PyQt5.QtCore import QThread, pyqtSignal
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Type, Set, Tuple
|
from typing import List, Type, Set, Tuple
|
||||||
|
|
||||||
import requests
|
|
||||||
from PyQt5.QtCore import QThread, pyqtSignal
|
|
||||||
|
|
||||||
from bauh import LOGS_PATH
|
from bauh import LOGS_PATH
|
||||||
from bauh.api.abstract.cache import MemoryCache
|
from bauh.api.abstract.cache import MemoryCache
|
||||||
from bauh.api.abstract.controller import SoftwareManager, UpgradeRequirement, UpgradeRequirements
|
from bauh.api.abstract.controller import SoftwareManager, UpgradeRequirement, UpgradeRequirements
|
||||||
@@ -83,7 +82,7 @@ class AsyncAction(QThread, ProcessWatcher):
|
|||||||
def show_message(self, title: str, body: str, type_: MessageType = MessageType.INFO):
|
def show_message(self, title: str, body: str, type_: MessageType = MessageType.INFO):
|
||||||
self.signal_message.emit({'title': title, 'body': body, 'type': type_})
|
self.signal_message.emit({'title': title, 'body': body, 'type': type_})
|
||||||
|
|
||||||
def notify_finished(self, res: object):
|
def notify_finished(self, res: object = None):
|
||||||
self.signal_finished.emit(res)
|
self.signal_finished.emit(res)
|
||||||
|
|
||||||
def change_status(self, status: str):
|
def change_status(self, status: str):
|
||||||
@@ -534,68 +533,68 @@ class UninstallPackage(AsyncAction):
|
|||||||
self.root_pwd = None
|
self.root_pwd = None
|
||||||
|
|
||||||
|
|
||||||
class DowngradeApp(AsyncAction):
|
class DowngradePackage(AsyncAction):
|
||||||
|
|
||||||
def __init__(self, manager: SoftwareManager, i18n: I18n, app: PackageView = None):
|
def __init__(self, manager: SoftwareManager, i18n: I18n, pkg: PackageView = None):
|
||||||
super(DowngradeApp, self).__init__()
|
super(DowngradePackage, self).__init__()
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
self.app = app
|
self.pkg = pkg
|
||||||
self.i18n = i18n
|
self.i18n = i18n
|
||||||
self.root_pwd = None
|
self.root_pwd = None
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if self.app:
|
if self.pkg:
|
||||||
success = False
|
success = False
|
||||||
|
|
||||||
if self.app.model.supports_backup():
|
if self.pkg.model.supports_backup():
|
||||||
if not self.request_backup(read_config(), 'downgrade', self.i18n, self.root_pwd):
|
if not self.request_backup(read_config(), 'downgrade', self.i18n, self.root_pwd):
|
||||||
self.notify_finished({'app': self.app, 'success': success})
|
self.notify_finished({'app': self.pkg, 'success': success})
|
||||||
self.app = None
|
self.pkg = None
|
||||||
self.root_pwd = None
|
self.root_pwd = None
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
success = self.manager.downgrade(self.app.model, self.root_pwd, self)
|
success = self.manager.downgrade(self.pkg.model, self.root_pwd, self)
|
||||||
except (requests.exceptions.ConnectionError, NoInternetException) as e:
|
except (requests.exceptions.ConnectionError, NoInternetException) as e:
|
||||||
success = False
|
success = False
|
||||||
self.print(self.i18n['internet.required'])
|
self.print(self.i18n['internet.required'])
|
||||||
finally:
|
finally:
|
||||||
self.notify_finished({'app': self.app, 'success': success})
|
self.notify_finished({'app': self.pkg, 'success': success})
|
||||||
self.app = None
|
self.pkg = None
|
||||||
self.root_pwd = None
|
self.root_pwd = None
|
||||||
|
|
||||||
|
|
||||||
class GetAppInfo(AsyncAction):
|
class ShowPackageInfo(AsyncAction):
|
||||||
|
|
||||||
def __init__(self, manager: SoftwareManager, app: PackageView = None):
|
def __init__(self, manager: SoftwareManager, pkg: PackageView = None):
|
||||||
super(GetAppInfo, self).__init__()
|
super(ShowPackageInfo, self).__init__()
|
||||||
self.app = app
|
self.pkg = pkg
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if self.app:
|
if self.pkg:
|
||||||
info = {'__app__': self.app}
|
info = {'__app__': self.pkg}
|
||||||
info.update(self.manager.get_info(self.app.model))
|
info.update(self.manager.get_info(self.pkg.model))
|
||||||
self.notify_finished(info)
|
self.notify_finished(info)
|
||||||
self.app = None
|
self.pkg = None
|
||||||
|
|
||||||
|
|
||||||
class GetAppHistory(AsyncAction):
|
class ShowPackageHistory(AsyncAction):
|
||||||
|
|
||||||
def __init__(self, manager: SoftwareManager, i18n: I18n, app: PackageView = None):
|
def __init__(self, manager: SoftwareManager, i18n: I18n, pkg: PackageView = None):
|
||||||
super(GetAppHistory, self).__init__()
|
super(ShowPackageHistory, self).__init__()
|
||||||
self.app = app
|
self.pkg = pkg
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
self.i18n = i18n
|
self.i18n = i18n
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if self.app:
|
if self.pkg:
|
||||||
try:
|
try:
|
||||||
self.notify_finished({'history': self.manager.get_history(self.app.model)})
|
self.notify_finished({'history': self.manager.get_history(self.pkg.model)})
|
||||||
except (requests.exceptions.ConnectionError, NoInternetException) as e:
|
except (requests.exceptions.ConnectionError, NoInternetException) as e:
|
||||||
self.notify_finished({'error': self.i18n['internet.required']})
|
self.notify_finished({'error': self.i18n['internet.required']})
|
||||||
finally:
|
finally:
|
||||||
self.app = None
|
self.pkg = None
|
||||||
|
|
||||||
|
|
||||||
class SearchPackages(AsyncAction):
|
class SearchPackages(AsyncAction):
|
||||||
@@ -816,21 +815,22 @@ class ListWarnings(QThread):
|
|||||||
self.signal_warnings.emit(warnings)
|
self.signal_warnings.emit(warnings)
|
||||||
|
|
||||||
|
|
||||||
class LaunchApp(AsyncAction):
|
class LaunchPackage(AsyncAction):
|
||||||
|
|
||||||
def __init__(self, manager: SoftwareManager, app: PackageView = None):
|
def __init__(self, manager: SoftwareManager, pkg: PackageView = None):
|
||||||
super(LaunchApp, self).__init__()
|
super(LaunchPackage, self).__init__()
|
||||||
self.app = app
|
self.pkg = pkg
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
if self.pkg:
|
||||||
if self.app:
|
|
||||||
try:
|
try:
|
||||||
time.sleep(0.25)
|
time.sleep(0.25)
|
||||||
self.manager.launch(self.app.model)
|
self.manager.launch(self.pkg.model)
|
||||||
self.notify_finished(True)
|
self.notify_finished(True)
|
||||||
except:
|
except:
|
||||||
|
traceback.print_exc()
|
||||||
|
finally:
|
||||||
self.notify_finished(False)
|
self.notify_finished(False)
|
||||||
|
|
||||||
|
|
||||||
@@ -910,7 +910,7 @@ class ApplyFilters(AsyncAction):
|
|||||||
while self.wait_table_update:
|
while self.wait_table_update:
|
||||||
time.sleep(0.005)
|
time.sleep(0.005)
|
||||||
|
|
||||||
self.notify_finished(True)
|
self.notify_finished()
|
||||||
|
|
||||||
|
|
||||||
class CustomAction(AsyncAction):
|
class CustomAction(AsyncAction):
|
||||||
@@ -948,10 +948,10 @@ class CustomAction(AsyncAction):
|
|||||||
self.root_pwd = None
|
self.root_pwd = None
|
||||||
|
|
||||||
|
|
||||||
class GetScreenshots(AsyncAction):
|
class ShowScreenshots(AsyncAction):
|
||||||
|
|
||||||
def __init__(self, manager: SoftwareManager, pkg: PackageView = None):
|
def __init__(self, manager: SoftwareManager, pkg: PackageView = None):
|
||||||
super(GetScreenshots, self).__init__()
|
super(ShowScreenshots, self).__init__()
|
||||||
self.pkg = pkg
|
self.pkg = pkg
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
from PyQt5.QtCore import Qt
|
|
||||||
from PyQt5.QtGui import QIcon, QPixmap
|
|
||||||
|
|
||||||
from bauh.view.util import resource
|
|
||||||
|
|
||||||
|
|
||||||
def load_icon(path: str, width: int, height: int = None) -> QIcon:
|
|
||||||
return QIcon(QPixmap(path).scaled(width, height if height else width, Qt.KeepAspectRatio, Qt.SmoothTransformation))
|
|
||||||
|
|
||||||
|
|
||||||
def load_resource_icon(path: str, width: int, height: int = None) -> QIcon:
|
|
||||||
return load_icon(resource.get_path(path), width, height)
|
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user