diff --git a/bauh/core/controller.py b/bauh/core/controller.py
index 55283474..316f8227 100755
--- a/bauh/core/controller.py
+++ b/bauh/core/controller.py
@@ -5,7 +5,7 @@ from typing import List, Set, Type
from bauh_api.abstract.controller import SoftwareManager, SearchResult, ApplicationContext
from bauh_api.abstract.disk import DiskCacheLoader
from bauh_api.abstract.handler import ProcessWatcher
-from bauh_api.abstract.model import SoftwarePackage, PackageUpdate, PackageHistory, PackageSuggestion
+from bauh_api.abstract.model import SoftwarePackage, PackageUpdate, PackageHistory, PackageSuggestion, PackageAction
SUGGESTIONS_LIMIT = 5
@@ -274,3 +274,9 @@ class GenericSoftwareManager(SoftwareManager):
suggestions.sort(key=lambda s: s.priority.value, reverse=True)
return suggestions
+
+ def execute_custom_action(self, action: PackageAction, pkg: SoftwarePackage, root_password: str, watcher: ProcessWatcher):
+ man = self._get_manager_for(pkg)
+
+ if man:
+ return exec('man.{}(pkg=pkg, root_password=root_password, watcher=watcher)'.format(action.manager_method))
diff --git a/bauh/resources/img/flathub.svg b/bauh/resources/img/flathub.svg
deleted file mode 100755
index 1b44a5d4..00000000
--- a/bauh/resources/img/flathub.svg
+++ /dev/null
@@ -1,179 +0,0 @@
-
-
-
-
diff --git a/bauh/resources/img/new_refresh.svg b/bauh/resources/img/new_refresh.svg
deleted file mode 100755
index c82e9923..00000000
--- a/bauh/resources/img/new_refresh.svg
+++ /dev/null
@@ -1,129 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/bauh/resources/img/refresh.svg b/bauh/resources/img/refresh.svg
index 16952792..c82e9923 100755
--- a/bauh/resources/img/refresh.svg
+++ b/bauh/resources/img/refresh.svg
@@ -7,39 +7,22 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Capa_1"
x="0px"
y="0px"
- width="48"
- height="48"
- viewBox="0 0 47.999999 47.999999"
+ width="24.052713"
+ height="24.049257"
+ viewBox="0 0 24.052713 24.049257"
xml:space="preserve"
- sodipodi:docname="refresh_2.svg"
- inkscape:version="0.92.3 (2405546, 2018-03-11)">image/svg+xml
+ transform="matrix(0.05273507,0,0,0.04925805,-0.82068209,0.02462902)"
+ style="fill:#ffffff;fill-opacity:1;stroke:#808080">
+ style="fill:#ffffff;fill-opacity:1;stroke:#808080">
+ style="fill:#ffffff;fill-opacity:1;stroke:#808080" />
+ style="fill:#ffffff;fill-opacity:1;stroke:#808080" />
+ transform="translate(-16.035798,-463.20537)">
+ transform="translate(-16.035798,-463.20537)">
+ transform="translate(-16.035798,-463.20537)">
+ transform="translate(-16.035798,-463.20537)">
+ transform="translate(-16.035798,-463.20537)">
+ transform="translate(-16.035798,-463.20537)">
+ transform="translate(-16.035798,-463.20537)">
+ transform="translate(-16.035798,-463.20537)">
+ transform="translate(-16.035798,-463.20537)">
+ transform="translate(-16.035798,-463.20537)">
+ transform="translate(-16.035798,-463.20537)">
+ transform="translate(-16.035798,-463.20537)">
+ transform="translate(-16.035798,-463.20537)">
+ transform="translate(-16.035798,-463.20537)">
+ transform="translate(-16.035798,-463.20537)">
\ No newline at end of file
diff --git a/bauh/resources/img/update_green.svg b/bauh/resources/img/update_green.svg
deleted file mode 100755
index d4fc7a00..00000000
--- a/bauh/resources/img/update_green.svg
+++ /dev/null
@@ -1,117 +0,0 @@
-
-
diff --git a/bauh/resources/img/update_logo.svg b/bauh/resources/img/update_logo.svg
deleted file mode 100644
index a57daece..00000000
--- a/bauh/resources/img/update_logo.svg
+++ /dev/null
@@ -1,179 +0,0 @@
-
-
-
-
diff --git a/bauh/view/qt/apps_table.py b/bauh/view/qt/apps_table.py
index 5d791ec0..2f6a60ce 100644
--- a/bauh/view/qt/apps_table.py
+++ b/bauh/view/qt/apps_table.py
@@ -91,7 +91,6 @@ class AppsTable(QTableWidget):
self.setSelectionBehavior(QTableView.SelectRows)
self.setHorizontalHeaderLabels(['' for _ in range(self.columnCount())])
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
- self.icon_flathub = QIcon(resource.get_path('img/flathub.svg'))
self.icon_logo = QIcon(resource.get_path('img/logo.svg'))
self.network_man = QNetworkAccessManager()
@@ -103,49 +102,56 @@ class AppsTable(QTableWidget):
self.cache_type_icon = {}
self.i18n = self.window.i18n
- def has_any_settings(self, app_v: PackageView):
- return app_v.model.can_be_refreshed() or \
- app_v.model.has_history() or \
- app_v.model.can_be_downgraded()
+ def has_any_settings(self, pkg: PackageView):
+ return pkg.model.has_history() or \
+ pkg.model.can_be_downgraded() or \
+ bool(pkg.model.get_custom_supported_actions())
- def show_pkg_settings(self, pkgv: PackageView):
+ def show_pkg_settings(self, pkg: PackageView):
menu_row = QMenu()
- if pkgv.model.installed:
- if pkgv.model.can_be_refreshed():
- action_history = QAction(self.i18n["manage_window.apps_table.row.actions.refresh"])
- action_history.setIcon(QIcon(resource.get_path('img/refresh.svg')))
-
- def refresh():
- self.window.refresh(pkgv)
-
- action_history.triggered.connect(refresh)
- menu_row.addAction(action_history)
-
- if pkgv.model.has_history():
+ if pkg.model.installed:
+ if pkg.model.has_history():
action_history = QAction(self.i18n["manage_window.apps_table.row.actions.history"])
action_history.setIcon(QIcon(resource.get_path('img/history.svg')))
def show_history():
- self.window.get_app_history(pkgv)
+ self.window.get_app_history(pkg)
action_history.triggered.connect(show_history)
menu_row.addAction(action_history)
- if pkgv.model.can_be_downgraded():
+ if pkg.model.can_be_downgraded():
action_downgrade = QAction(self.i18n["manage_window.apps_table.row.actions.downgrade"])
def downgrade():
if dialog.ask_confirmation(
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(pkgv)))),
+ body=self._parag(self.i18n['manage_window.apps_table.row.actions.downgrade.popup.body'].format(self._bold(str(pkg)))),
locale_keys=self.i18n):
- self.window.downgrade(pkgv)
+ self.window.downgrade(pkg)
action_downgrade.triggered.connect(downgrade)
action_downgrade.setIcon(QIcon(resource.get_path('img/downgrade.svg')))
menu_row.addAction(action_downgrade)
+ if bool(pkg.model.get_custom_supported_actions()):
+ for action in pkg.model.get_custom_supported_actions():
+ item = QAction(self.i18n[action.i18_label_key])
+
+ if action.icon_path:
+ item.setIcon(QIcon(action.icon_path))
+
+ def custom_action():
+ if dialog.ask_confirmation(
+ title=self.i18n[action.i18_label_key],
+ body=self._parag('{} {} ?'.format(self.i18n[action.i18_label_key], self._bold(str(pkg)))),
+ locale_keys=self.i18n):
+ self.window.execute_custom_action(pkg, action)
+
+ item.triggered.connect(custom_action)
+ menu_row.addAction(item)
+
menu_row.adjustSize()
menu_row.popup(QCursor.pos())
menu_row.exec_()
diff --git a/bauh/view/qt/thread.py b/bauh/view/qt/thread.py
index a4bafb1e..6ed1485e 100644
--- a/bauh/view/qt/thread.py
+++ b/bauh/view/qt/thread.py
@@ -8,7 +8,7 @@ from PyQt5.QtCore import QThread, pyqtSignal
from bauh_api.abstract.cache import MemoryCache
from bauh_api.abstract.controller import SoftwareManager
from bauh_api.abstract.handler import ProcessWatcher
-from bauh_api.abstract.model import PackageStatus, SoftwarePackage
+from bauh_api.abstract.model import PackageStatus, SoftwarePackage, PackageAction
from bauh_api.abstract.view import InputViewComponent, MessageType
from bauh_api.exception import NoInternetException
@@ -358,29 +358,6 @@ class VerifyModels(QThread):
self.apps = None
-class RefreshApp(AsyncAction):
-
- def __init__(self, manager: SoftwareManager, app: PackageView = None):
- super(RefreshApp, self).__init__()
- self.app = app
- self.manager = manager
- self.root_password = None
-
- def run(self):
-
- if self.app:
- success = False
-
- try:
- success = self.manager.refresh(self.app.model, self.root_password, self)
- except (requests.exceptions.ConnectionError, NoInternetException):
- success = False
- self.signal_output.emit(self.locale_keys['internet.required'])
- finally:
- self.app = None
- self.signal_finished.emit(success)
-
-
class FindSuggestions(AsyncAction):
def __init__(self, man: SoftwareManager):
@@ -452,3 +429,30 @@ class ApplyFilters(AsyncAction):
time.sleep(0.005)
self.notify_finished(True)
+
+
+class CustomAction(AsyncAction):
+
+ def __init__(self, manager: SoftwareManager, custom_action: PackageAction = None, pkg: PackageView = None, root_password: str = None):
+ super(CustomAction, self).__init__()
+ self.manager = manager
+ self.pkg = pkg
+ self.custom_action = custom_action
+ self.root_password = root_password
+
+ def run(self):
+ success = True
+ if self.pkg:
+ try:
+ success = self.manager.execute_custom_action(action=self.custom_action,
+ pkg=self.pkg.model,
+ root_password=self.root_password,
+ watcher=self)
+ except (requests.exceptions.ConnectionError, NoInternetException):
+ success = False
+ self.signal_output.emit(self.locale_keys['internet.required'])
+
+ self.notify_finished({'success': success, 'pkg': self.pkg})
+ self.pkg = None
+ self.custom_action = None
+ self.root_password = None
diff --git a/bauh/view/qt/window.py b/bauh/view/qt/window.py
index 18fb34db..246f8466 100755
--- a/bauh/view/qt/window.py
+++ b/bauh/view/qt/window.py
@@ -8,7 +8,7 @@ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QCheckBox, QHead
QLabel, QPlainTextEdit, QLineEdit, QProgressBar, QPushButton, QComboBox
from bauh_api.abstract.cache import MemoryCache
from bauh_api.abstract.controller import SoftwareManager
-from bauh_api.abstract.model import SoftwarePackage
+from bauh_api.abstract.model import SoftwarePackage, PackageAction
from bauh_api.abstract.view import MessageType
from bauh.core import resource
@@ -22,8 +22,8 @@ from bauh.view.qt.history import HistoryDialog
from bauh.view.qt.info import InfoDialog
from bauh.view.qt.root import is_root, ask_root_password
from bauh.view.qt.thread import UpdateSelectedApps, RefreshApps, UninstallApp, DowngradeApp, GetAppInfo, \
- GetAppHistory, SearchApps, InstallApp, AnimateProgress, VerifyModels, RefreshApp, FindSuggestions, ListWarnings, \
- AsyncAction, RunApp, ApplyFilters
+ GetAppHistory, SearchApps, 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
@@ -140,7 +140,7 @@ class ManageWindow(QWidget):
self.bt_refresh = QPushButton()
self.bt_refresh.setToolTip(i18n['manage_window.bt.refresh.tooltip'])
- self.bt_refresh.setIcon(QIcon(resource.get_path('img/new_refresh.svg')))
+ self.bt_refresh.setIcon(QIcon(resource.get_path('img/refresh.svg')))
self.bt_refresh.setText(self.i18n['manage_window.bt.refresh.text'])
self.bt_refresh.setStyleSheet(self._toolbar_button_style('#2368AD'))
self.bt_refresh.clicked.connect(lambda: self.refresh_apps(keep_console=False))
@@ -198,9 +198,9 @@ class ManageWindow(QWidget):
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_downgrade = self._bind_async_action(DowngradeApp(self.manager, self.i18n), finished_call=self._finish_downgrade)
- self.thread_refresh_app = self._bind_async_action(RefreshApp(manager=self.manager), finished_call=self._finish_refresh)
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)
+ self.thread_custom_action = self._bind_async_action(CustomAction(manager=self.manager), finished_call=self._finish_custom_action)
self.thread_apply_filters = ApplyFilters()
self.thread_apply_filters.signal_finished.connect(self._finish_apply_filters_async)
@@ -418,23 +418,6 @@ class ManageWindow(QWidget):
self.thread_run_app.app = app
self.thread_run_app.start()
- def refresh(self, app: PackageView):
- pwd = None
- requires_root = self.manager.requires_root('refresh', app.model)
-
- if not is_root() and requires_root:
- pwd, ok = ask_root_password(self.i18n)
-
- if not ok:
- return
-
- self._handle_console_option(True)
- self._begin_action('{} {}'.format(self.i18n['manage_window.status.refreshing_app'], app.model.name))
-
- self.thread_refresh_app.app = app
- self.thread_refresh_app.root_password = pwd
- self.thread_refresh_app.start()
-
def _finish_uninstall(self, pkgv: PackageView):
self.finish_action()
@@ -469,16 +452,6 @@ class ManageWindow(QWidget):
self.checkbox_console.setChecked(True)
- def _finish_refresh(self, success: bool):
- self.finish_action()
- self.update_bt_upgrade()
- self._update_type_filters()
-
- if success:
- self.refresh_apps()
- else:
- self.checkbox_console.setChecked(True)
-
def _change_label_status(self, status: str):
self.label_status.setText(status)
@@ -901,3 +874,27 @@ class ManageWindow(QWidget):
def _finish_run_app(self, success: bool):
self.finish_action()
+
+ def execute_custom_action(self, pkg: PackageView, action: PackageAction):
+ pwd = None
+
+ if not is_root() and action.requires_root:
+ pwd, ok = ask_root_password(self.i18n)
+
+ if not ok:
+ return
+
+ self._handle_console_option(True)
+ self._begin_action('{} {}'.format(self.i18n[action.i18n_status_key], pkg.model.name))
+
+ self.thread_custom_action.pkg = pkg
+ self.thread_custom_action.root_password = pwd
+ self.thread_custom_action.custom_action = action
+ self.thread_custom_action.start()
+
+ def _finish_custom_action(self, res: dict):
+ self.finish_action()
+ if res['success']:
+ self.refresh_apps(pkg_types={res['pkg'].model.__class__})
+ else:
+ self.checkbox_console.setChecked(True)