diff --git a/fpakman/core/controller.py b/fpakman/core/controller.py index eabf44a7..cea20876 100755 --- a/fpakman/core/controller.py +++ b/fpakman/core/controller.py @@ -1,11 +1,9 @@ -import time from abc import ABC, abstractmethod from argparse import Namespace -from threading import Lock from typing import List, Dict from fpakman.core.disk import DiskCacheLoader, DiskCacheLoaderFactory -from fpakman.core.model import Application +from fpakman.core.model import Application, ApplicationUpdate from fpakman.core.system import FpakmanProcess @@ -82,6 +80,10 @@ class ApplicationManager(ABC): """ pass + @abstractmethod + def list_updates(self) -> List[ApplicationUpdate]: + pass + class GenericApplicationManager(ApplicationManager): @@ -90,7 +92,6 @@ class GenericApplicationManager(ApplicationManager): self.managers = managers self.map = {m.get_app_type(): m for m in self.managers} self.disk_loader_factory = disk_loader_factory - self.lock_read = Lock() self._enabled_map = {} if app_args.check_packaging_once else None self.prepare() @@ -131,57 +132,48 @@ class GenericApplicationManager(ApplicationManager): return man.is_enabled() def search(self, word: str, disk_loader: DiskCacheLoader = None) -> Dict[str, List[Application]]: - self.lock_read.acquire() - try: - res = {'installed': [], 'new': []} + res = {'installed': [], 'new': []} - norm_word = word.strip().lower() - disk_loader = None + norm_word = word.strip().lower() + disk_loader = None - for man in self.managers: - if self._is_enabled(man): - if not disk_loader: - disk_loader = self.disk_loader_factory.new() - disk_loader.start() + for man in self.managers: + if self._is_enabled(man): + if not disk_loader: + disk_loader = self.disk_loader_factory.new() + disk_loader.start() - apps_found = man.search(word=norm_word, disk_loader=disk_loader) - res['installed'].extend(apps_found['installed']) - res['new'].extend(apps_found['new']) + apps_found = man.search(word=norm_word, disk_loader=disk_loader) + res['installed'].extend(apps_found['installed']) + res['new'].extend(apps_found['new']) - disk_loader.stop = True - disk_loader.join() + disk_loader.stop = True + disk_loader.join() - for key in res: - res[key] = self._sort(res[key], norm_word) + for key in res: + res[key] = self._sort(res[key], norm_word) - return res - finally: - self.lock_read.release() + return res def read_installed(self, disk_loader: DiskCacheLoader = None) -> List[Application]: - self.lock_read.acquire() + installed = [] - try: - installed = [] + disk_loader = None - disk_loader = None + for man in self.managers: + if self._is_enabled(man): + if not disk_loader: + disk_loader = self.disk_loader_factory.new() + disk_loader.start() - for man in self.managers: - if self._is_enabled(man): - if not disk_loader: - disk_loader = self.disk_loader_factory.new() - disk_loader.start() + installed.extend(man.read_installed(disk_loader=disk_loader)) - installed.extend(man.read_installed(disk_loader=disk_loader)) + disk_loader.stop = True + disk_loader.join() - disk_loader.stop = True - disk_loader.join() + installed.sort(key=lambda a: a.base_data.name.lower()) - installed.sort(key=lambda a: a.base_data.name.lower()) - - return installed - finally: - self.lock_read.release() + return installed def can_downgrade(self): return True @@ -260,8 +252,17 @@ class GenericApplicationManager(ApplicationManager): return man.refresh(app, root_password) def prepare(self): - if self.managers: for man in self.managers: if self._is_enabled(man): man.prepare() + + def list_updates(self) -> List[ApplicationUpdate]: + updates = [] + + if self.managers: + for man in self.managers: + if self._is_enabled(man): + updates.extend(man.list_updates()) + + return updates diff --git a/fpakman/core/flatpak/controller.py b/fpakman/core/flatpak/controller.py index e9be83f2..f0298e25 100644 --- a/fpakman/core/flatpak/controller.py +++ b/fpakman/core/flatpak/controller.py @@ -9,8 +9,8 @@ from fpakman.core.controller import ApplicationManager from fpakman.core.disk import DiskCacheLoader from fpakman.core.flatpak import flatpak from fpakman.core.flatpak.model import FlatpakApplication -from fpakman.core.flatpak.worker import FlatpakAsyncDataLoader -from fpakman.core.model import ApplicationData +from fpakman.core.flatpak.worker import FlatpakAsyncDataLoader, FlatpakUpdateLoader +from fpakman.core.model import ApplicationData, ApplicationUpdate from fpakman.core.system import FpakmanProcess from fpakman.util.cache import Cache @@ -148,3 +148,33 @@ class FlatpakManager(ApplicationManager): def prepare(self): flatpak.set_default_remotes() + + def list_updates(self) -> List[ApplicationUpdate]: + updates = [] + installed = flatpak.list_installed(extra_fields=False) + + if installed: + available_updates = flatpak.list_updates_as_str() + + if available_updates: + loaders = None + + for app_json in installed: + if app_json['id'] in available_updates: + loader = FlatpakUpdateLoader(app=app_json, http_session=self.http_session) + loader.start() + + if loaders is None: + loaders = [] + + loaders.append(loader) + + if loaders: + for loader in loaders: + loader.join() + app = loader.app + updates.append(ApplicationUpdate(app_id='{}:{}'.format(app['id'], app['branch']), + app_type='flatpak', + version=app.get('version'))) + + return updates diff --git a/fpakman/core/flatpak/flatpak.py b/fpakman/core/flatpak/flatpak.py index 8de12ddf..f22cd646 100755 --- a/fpakman/core/flatpak/flatpak.py +++ b/fpakman/core/flatpak/flatpak.py @@ -1,6 +1,6 @@ import re import subprocess -from typing import List +from typing import List, Set from fpakman.core import system from fpakman.core.exception import NoInternetException @@ -8,7 +8,7 @@ from fpakman.core.exception import NoInternetException BASE_CMD = 'flatpak' -def app_str_to_json(line: str, version: str) -> dict: +def app_str_to_json(line: str, version: str, extra_fields: bool = True) -> dict: app_array = line.split('\t') @@ -17,18 +17,21 @@ def app_str_to_json(line: str, version: str) -> dict: 'id': app_array[1], 'version': app_array[2], 'branch': app_array[3]} - elif '1.0' <= version < '1.1': - app = {'ref': app_array[0], 'options': app_array[1]} - ref_data = app['ref'].split('/') - app['id'] = ref_data[0] - app['arch'] = ref_data[1] - app['branch'] = ref_data[2] - app['name'] = ref_data[0].split('.')[-1] - app['version'] = None + elif '1.0' <= version < '1.1': + + ref_data = app_array[0].split('/') + + app = {'id': ref_data[0], + 'arch': ref_data[1], + 'name': ref_data[0].split('.')[-1], + 'ref': app_array[0], + 'options': app_array[1], + 'branch': ref_data[2], + 'version': None} elif '1.2' <= version < '1.3': - app = {'name': app_array[1].strip().split('.')[-1], - 'id': app_array[1], + app = {'id': app_array[1], + 'name': app_array[1].strip().split('.')[-1], 'version': app_array[2], 'branch': app_array[3], 'arch': app_array[4], @@ -36,8 +39,9 @@ def app_str_to_json(line: str, version: str) -> dict: else: raise Exception('Unsupported version') - extra_fields = get_app_info_fields(app['id'], app['branch'], ['origin', 'arch', 'ref', 'commit'], check_runtime=True) - app.update(extra_fields) + if extra_fields: + extra_fields = get_app_info_fields(app['id'], app['branch'], ['origin', 'arch', 'ref', 'commit'], check_runtime=True) + app.update(extra_fields) return app @@ -81,13 +85,13 @@ def get_app_info(app_id: str, branch: str): return system.run_cmd('{} info {} {}'.format(BASE_CMD, app_id, branch)) -def list_installed() -> List[dict]: +def list_installed(extra_fields: bool = True) -> List[dict]: apps_str = system.run_cmd('{} list'.format(BASE_CMD)) if apps_str: version = get_version() app_lines = apps_str.split('\n') - return [app_str_to_json(line, version) for line in app_lines if line] + return [app_str_to_json(line, version, extra_fields=extra_fields) for line in app_lines if line] return [] @@ -215,4 +219,3 @@ def install_and_stream(app_id: str, origin: str): def set_default_remotes(): system.run_cmd('flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo') - diff --git a/fpakman/core/flatpak/worker.py b/fpakman/core/flatpak/worker.py index dc85e384..c3206b5f 100644 --- a/fpakman/core/flatpak/worker.py +++ b/fpakman/core/flatpak/worker.py @@ -1,9 +1,11 @@ import time import traceback +from threading import Thread from colorama import Fore from fpakman.core.controller import ApplicationManager +from fpakman.core.flatpak import flatpak from fpakman.core.flatpak.constants import FLATHUB_API_URL, FLATHUB_URL from fpakman.core.flatpak.model import FlatpakApplication from fpakman.core.model import ApplicationStatus @@ -82,3 +84,41 @@ class FlatpakAsyncDataLoader(AsyncDataLoader): http_session=self.http_session, timeout=self.timeout, app=self.app) + + +class FlatpakUpdateLoader(Thread): + + def __init__(self, app: dict, http_session, attempts: int = 2, timeout: int = 20): + super(FlatpakUpdateLoader, self).__init__(daemon=True) + self.app = app + self.http_session = http_session + self.attempts = attempts + self.timeout = timeout + + def run(self): + + if self.app.get('ref') is None: + self.app.update(flatpak.get_app_info_fields(self.app['id'], self.app['branch'], fields=['ref'], check_runtime=True)) + else: + self.app['runtime'] = self.app['ref'].startswith('runtime/') + + if not self.app['runtime']: + current_attempts = 0 + + while current_attempts < self.attempts: + + current_attempts += 1 + + try: + res = self.http_session.get('{}/apps/{}'.format(FLATHUB_API_URL, self.app['id']), timeout=self.timeout) + + if res.status_code == 200 and res.text: + data = res.json() + + if data.get('currentReleaseVersion'): + self.app['version'] = data['currentReleaseVersion'] + + break + except: + traceback.print_exc() + time.sleep(0.5) diff --git a/fpakman/core/model.py b/fpakman/core/model.py index df63b7d4..2c867bda 100644 --- a/fpakman/core/model.py +++ b/fpakman/core/model.py @@ -86,3 +86,14 @@ class Application(ABC): def __str__(self): return '{} (id={}, name={})'.format(self.__class__.__name__, self.base_data.id, self.base_data.name) + + +class ApplicationUpdate: + + def __init__(self, app_id: str, version: str, app_type: str): + self.id = app_id + self.version = version + self.type = app_type + + def __str__(self): + return '{} (id={}, type={}, new_version={})'.format(self.__class__.__name__, self.id, self.type, self.type) diff --git a/fpakman/core/snap/controller.py b/fpakman/core/snap/controller.py index 3c495064..4f53ee27 100644 --- a/fpakman/core/snap/controller.py +++ b/fpakman/core/snap/controller.py @@ -7,7 +7,7 @@ from typing import Dict, List from fpakman.core import disk from fpakman.core.controller import ApplicationManager from fpakman.core.disk import DiskCacheLoader -from fpakman.core.model import ApplicationData, Application +from fpakman.core.model import ApplicationData, Application, ApplicationUpdate from fpakman.core.snap import snap from fpakman.core.snap.model import SnapApplication from fpakman.core.snap.worker import SnapAsyncDataLoader @@ -131,3 +131,6 @@ class SnapManager(ApplicationManager): def prepare(self): pass + + def list_updates(self) -> List[ApplicationUpdate]: + return [] diff --git a/fpakman/view/qt/apps_table.py b/fpakman/view/qt/apps_table.py index 71b61491..e4113f5b 100644 --- a/fpakman/view/qt/apps_table.py +++ b/fpakman/view/qt/apps_table.py @@ -119,9 +119,6 @@ class AppsTable(QTableWidget): menu_row.exec_() def fill_async_data(self): - - self.lock_async_data.acquire() - if self.window.apps: for idx, app_v in enumerate(self.window.apps): @@ -142,8 +139,6 @@ class AppsTable(QTableWidget): self.window.resize_and_center() - self.lock_async_data.release() - def get_selected_app(self) -> ApplicationView: return self.window.apps[self.currentRow()] @@ -202,9 +197,9 @@ class AppsTable(QTableWidget): if not icon_was_cached or not os.path.exists(app.model.get_disk_icon_path()): self.window.manager.cache_to_disk(app=app.model, icon_bytes=icon_data['bytes'], only_icon=True) - def update_apps(self, app_views: List[ApplicationView]): - self.setEnabled(True) + def update_apps(self, app_views: List[ApplicationView], update_check_enabled: bool = True): self.setRowCount(len(app_views) if app_views else 0) + self.setEnabled(True) if app_views: for idx, app_v in enumerate(app_views): @@ -214,7 +209,11 @@ class AppsTable(QTableWidget): self._set_col_type(idx, app_v) self._set_col_installed(idx, app_v) - col_update = UpdateToggleButton(app_v, self.window, self.window.locale_keys, app_v.model.update) if app_v.model.update else None + col_update = None + + if update_check_enabled and app_v.model.update: + col_update = UpdateToggleButton(app_v, self.window, self.window.locale_keys, app_v.model.update) + self.setCellWidget(idx, 5, col_update) def _set_col_installed(self, idx: int, app_v: ApplicationView): diff --git a/fpakman/view/qt/systray.py b/fpakman/view/qt/systray.py index fb0cacef..901a914f 100755 --- a/fpakman/view/qt/systray.py +++ b/fpakman/view/qt/systray.py @@ -6,9 +6,10 @@ from PyQt5.QtCore import QThread, pyqtSignal, QCoreApplication, Qt, QSize from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import QSystemTrayIcon, QMenu +from fpakman import __app_name__ from fpakman.core import resource, system from fpakman.core.controller import ApplicationManager -from fpakman.core.model import Application +from fpakman.core.model import ApplicationUpdate from fpakman.util.cache import Cache from fpakman.view.qt.about import AboutDialog from fpakman.view.qt.window import ManageWindow @@ -27,9 +28,7 @@ class UpdateCheck(QThread): while True: - apps = self.manager.read_installed() - - updates = [app for app in apps if app.update] + updates = self.manager.list_updates() if updates: self.signal.emit(updates) @@ -66,30 +65,32 @@ class TrayIcon(QSystemTrayIcon): self.setContextMenu(self.menu) self.manage_window = None + self.dialog_about = None self.check_thread = UpdateCheck(check_interval=check_interval, manager=self.manager) self.check_thread.signal.connect(self.notify_updates) self.check_thread.start() - self.dialog_about = None - self.last_updates = set() self.update_notification = update_notification self.lock_notify = Lock() self.activated.connect(self.handle_click) + self.set_default_tooltip() + + def set_default_tooltip(self): + self.setToolTip('{} ({})'.format(self.locale_keys['manage_window.title'], __app_name__)) def handle_click(self, reason): if reason == self.Trigger: self.show_manage_window() - def notify_updates(self, updates: List[Application]): + def notify_updates(self, updates: List[ApplicationUpdate]): self.lock_notify.acquire() try: if len(updates) > 0: - - update_keys = {'{}:{}'.format(app.base_data.id, app.base_data.version) for app in updates} + update_keys = {'{}:{}:{}'.format(up.type, up.id, up.version) for up in updates} new_icon = self.icon_update @@ -103,7 +104,7 @@ class TrayIcon(QSystemTrayIcon): else: new_icon = self.icon_default - self.setToolTip(None) + self.set_default_tooltip() if self.icon().cacheKey() != new_icon.cacheKey(): # changes the icon if needed self.setIcon(new_icon) diff --git a/fpakman/view/qt/thread.py b/fpakman/view/qt/thread.py index e30dd21b..1b91f450 100644 --- a/fpakman/view/qt/thread.py +++ b/fpakman/view/qt/thread.py @@ -302,6 +302,8 @@ class VerifyModels(QThread): if stop_at <= datetime.utcnow(): break + time.sleep(0.1) + self.apps = None diff --git a/fpakman/view/qt/window.py b/fpakman/view/qt/window.py index b35e2793..09f26e2f 100755 --- a/fpakman/view/qt/window.py +++ b/fpakman/view/qt/window.py @@ -1,6 +1,5 @@ import operator from functools import reduce -from threading import Lock from typing import List, Set from PyQt5.QtCore import QEvent, Qt @@ -31,7 +30,6 @@ class ManageWindow(QWidget): self.locale_keys = locale_keys self.manager = manager self.tray_icon = tray_icon - self.thread_lock = Lock() self.working = False # restrict the number of threaded actions self.apps = [] self.label_flatpak = None @@ -42,7 +40,6 @@ class ManageWindow(QWidget): self.icon_flathub = QIcon(resource.get_path('img/logo.svg')) self.resize(ManageWindow.__BASE_HEIGHT__, ManageWindow.__BASE_HEIGHT__) - self.setWindowTitle(locale_keys['manage_window.title']) self.setWindowIcon(self.icon_flathub) self.layout = QVBoxLayout() @@ -111,7 +108,7 @@ class ManageWindow(QWidget): self.bt_upgrade.setIcon(QIcon(resource.get_path('img/update_green.svg'))) self.bt_upgrade.setEnabled(False) self.bt_upgrade.clicked.connect(self.update_selected) - toolbar.addWidget(self.bt_upgrade) + self.ref_bt_upgrade = toolbar.addWidget(self.bt_upgrade) self.layout.addWidget(toolbar) @@ -235,25 +232,6 @@ class ManageWindow(QWidget): self.hide() self._handle_console_option(False) - def _acquire_lock(self): - - self.thread_lock.acquire() - - if not self.working: - self.working = True - - self.thread_lock.release() - return self.working - - def _release_lock(self): - - self.thread_lock.acquire() - - if self.working: - self.working = False - - self.thread_lock.release() - def _handle_console(self, checked: bool): if checked: @@ -271,69 +249,59 @@ class ManageWindow(QWidget): self.textarea_output.hide() def refresh_apps(self, keep_console: bool = True): + self.filter_types.clear() + self.input_search.clear() - if self._acquire_lock(): - self.filter_types.clear() - self.input_search.clear() + if not keep_console: + self._handle_console_option(False) - if not keep_console: - self._handle_console_option(False) - - self.ref_checkbox_updates.setVisible(False) - self.ref_checkbox_only_apps.setVisible(False) - self._begin_action(self.locale_keys['manage_window.status.refreshing'], clear_filters=True) - - self.thread_refresh.start() + self.ref_checkbox_updates.setVisible(False) + self.ref_checkbox_only_apps.setVisible(False) + self._begin_action(self.locale_keys['manage_window.status.refreshing'], clear_filters=True) + self.thread_refresh.start() def _finish_refresh_apps(self, apps: List[Application]): self.update_apps(apps) self.finish_action() self.ref_checkbox_only_apps.setVisible(True) - self._release_lock() + self.ref_bt_upgrade.setVisible(True) def uninstall_app(self, app: ApplicationView): - if self._acquire_lock(): + pwd = None + requires_root = self.manager.requires_root('uninstall', self.table_apps.get_selected_app().model) - pwd = None - requires_root = self.manager.requires_root('uninstall', self.table_apps.get_selected_app().model) + if not is_root() and requires_root: + pwd, ok = ask_root_password(self.locale_keys) - if not is_root() and requires_root: - pwd, ok = ask_root_password(self.locale_keys) + if not ok: + return - if not ok: - self._release_lock() - return + self._handle_console_option(True) + self._begin_action('{} {}'.format(self.locale_keys['manage_window.status.uninstalling'], app.model.base_data.name)) - self._handle_console_option(True) - self._begin_action('{} {}'.format(self.locale_keys['manage_window.status.uninstalling'], app.model.base_data.name)) - - self.thread_uninstall.app = app - self.thread_uninstall.root_password = pwd - self.thread_uninstall.start() + self.thread_uninstall.app = app + self.thread_uninstall.root_password = pwd + self.thread_uninstall.start() def refresh(self, app: ApplicationView): - if self._acquire_lock(): + pwd = None + requires_root = self.manager.requires_root('refresh', self.table_apps.get_selected_app().model) - pwd = None - requires_root = self.manager.requires_root('refresh', self.table_apps.get_selected_app().model) + if not is_root() and requires_root: + pwd, ok = ask_root_password(self.locale_keys) - if not is_root() and requires_root: - pwd, ok = ask_root_password(self.locale_keys) + if not ok: + return - if not ok: - self._release_lock() - return + self._handle_console_option(True) + self._begin_action('{} {}'.format(self.locale_keys['manage_window.status.refreshing'], app.model.base_data.name)) - self._handle_console_option(True) - self._begin_action('{} {}'.format(self.locale_keys['manage_window.status.refreshing'], app.model.base_data.name)) - - self.thread_refresh_app.app = app - self.thread_refresh_app.root_password = pwd - self.thread_refresh_app.start() + self.thread_refresh_app.app = app + self.thread_refresh_app.root_password = pwd + self.thread_refresh_app.start() def _finish_uninstall(self, success: bool): self.finish_action() - self._release_lock() if success: if self._can_notify_user(): @@ -353,7 +321,6 @@ class ManageWindow(QWidget): def _finish_downgrade(self, success: bool): self.finish_action() - self._release_lock() if success: if self._can_notify_user(): @@ -365,17 +332,16 @@ class ManageWindow(QWidget): if self._can_notify_user(): system.notify_user(self.locale_keys['notification.downgrade.failed']) - self.change_update_state(notify_tray=False) + self.change_update_state() self.checkbox_console.setChecked(True) def _finish_refresh(self, success: bool): self.finish_action() - self._release_lock() if success: self.refresh_apps() else: - self.change_update_state(notify_tray=False) + self.change_update_state() self.checkbox_console.setChecked(True) def apply_filters(self): @@ -399,11 +365,9 @@ class ManageWindow(QWidget): self.table_apps.change_headers_policy() self.resize_and_center(accept_lower_width=visible_apps > 0) - def change_update_state(self, notify_tray: bool = True, change_filters: bool = True): - + def change_update_state(self, change_filters: bool = True): enable_bt_update = False - - app_updates, library_updates = 0, 0 + app_updates, library_updates, not_installed = 0, 0, 0 for app_v in self.apps: if app_v.model.update: @@ -412,28 +376,33 @@ class ManageWindow(QWidget): else: app_updates += 1 + if not app_v.model.installed: + not_installed += 1 + for app_v in self.apps: - if app_v.visible and app_v.update_checked: + if not_installed == 0 and app_v.visible and app_v.update_checked: enable_bt_update = True break self.bt_upgrade.setEnabled(enable_bt_update) total_updates = app_updates + library_updates + if total_updates > 0: self.label_updates.setPixmap(QPixmap(resource.get_path('img/exclamation.svg')).scaled(16, 16, Qt.KeepAspectRatio, Qt.SmoothTransformation)) self.label_updates.setToolTip('{}: {} ( {} {} | {} {} )'.format(self.locale_keys['manage_window.label.updates'], - total_updates, - app_updates, - self.locale_keys['manage_window.checkbox.only_apps'].lower(), - library_updates, - self.locale_keys['others'].lower())) + total_updates, + app_updates, + self.locale_keys['manage_window.checkbox.only_apps'].lower(), + library_updates, + self.locale_keys['others'].lower())) - if not self.ref_checkbox_updates.isVisible(): - self.ref_checkbox_updates.setVisible(True) + if not_installed == 0: + if not self.ref_checkbox_updates.isVisible(): + self.ref_checkbox_updates.setVisible(True) - if change_filters and not self.checkbox_updates.isChecked(): - self.checkbox_updates.setChecked(True) + if change_filters and not self.checkbox_updates.isChecked(): + self.checkbox_updates.setChecked(True) if change_filters and library_updates > 0 and self.checkbox_only_apps.isChecked(): self.checkbox_only_apps.setChecked(False) @@ -442,9 +411,6 @@ class ManageWindow(QWidget): self.ref_checkbox_updates.setVisible(False) self.label_updates.setPixmap(QPixmap()) - if notify_tray: - self.tray_icon.notify_updates([app.model for app in self.apps if app.model.update]) - def centralize(self): geo = self.frameGeometry() screen = QApplication.desktop().screenNumber(QApplication.desktop().cursor().pos()) @@ -452,7 +418,7 @@ class ManageWindow(QWidget): geo.moveCenter(center_point) self.move(geo.topLeft()) - def update_apps(self, apps: List[Application]): + def update_apps(self, apps: List[Application], update_check_enabled: bool = True): self.apps = [] napps = 0 # number of apps (not libraries) @@ -473,7 +439,7 @@ class ManageWindow(QWidget): self.checkbox_only_apps.setChecked(True) self._update_type_filters(available_types) - self.table_apps.update_apps(self.apps) + self.table_apps.update_apps(self.apps, update_check_enabled=update_check_enabled) self.apply_filters() self.change_update_state() self.resize_and_center() @@ -510,22 +476,19 @@ class ManageWindow(QWidget): self.centralize() def update_selected(self): + if self.apps: - if self._acquire_lock(): - if self.apps: + to_update = [app_v for app_v in self.apps if app_v.visible and app_v.update_checked] - to_update = [app_v for app_v in self.apps if app_v.visible and app_v.update_checked] + if to_update: + self._handle_console_option(True) - if to_update: - self._handle_console_option(True) - - self._begin_action(self.locale_keys['manage_window.status.upgrading']) - self.thread_update.apps_to_update = to_update - self.thread_update.start() + self._begin_action(self.locale_keys['manage_window.status.upgrading']) + self.thread_update.apps_to_update = to_update + self.thread_update.start() def _finish_update_selected(self, success: bool, updated: int): self.finish_action() - self._release_lock() if success: if self._can_notify_user(): @@ -581,51 +544,43 @@ class ManageWindow(QWidget): self.checkbox_updates.setEnabled(True) def downgrade_app(self, app: ApplicationView): - if self._acquire_lock(): + pwd = None + requires_root = self.manager.requires_root('downgrade', self.table_apps.get_selected_app().model) - pwd = None - requires_root = self.manager.requires_root('downgrade', self.table_apps.get_selected_app().model) + if not is_root() and requires_root: + pwd, ok = ask_root_password(self.locale_keys) - if not is_root() and requires_root: - pwd, ok = ask_root_password(self.locale_keys) + if not ok: + return - if not ok: - self._release_lock() - return + self._handle_console_option(True) + self._begin_action('{} {}'.format(self.locale_keys['manage_window.status.downgrading'], app.model.base_data.name)) - self._handle_console_option(True) - self._begin_action('{} {}'.format(self.locale_keys['manage_window.status.downgrading'], app.model.base_data.name)) - - self.thread_downgrade.app = app - self.thread_downgrade.root_password = pwd - self.thread_downgrade.start() + self.thread_downgrade.app = app + self.thread_downgrade.root_password = pwd + self.thread_downgrade.start() def get_app_info(self, app: dict): + self._handle_console_option(False) + self._begin_action(self.locale_keys['manage_window.status.info']) - if self._acquire_lock(): - self._handle_console_option(False) - self._begin_action(self.locale_keys['manage_window.status.info']) - - self.thread_get_info.app = app - self.thread_get_info.start() + self.thread_get_info.app = app + self.thread_get_info.start() def get_app_history(self, app: dict): - if self._acquire_lock(): - self._handle_console_option(False) - self._begin_action(self.locale_keys['manage_window.status.history']) + self._handle_console_option(False) + self._begin_action(self.locale_keys['manage_window.status.history']) - self.thread_get_history.app = app - self.thread_get_history.start() + self.thread_get_history.app = app + self.thread_get_history.start() def _finish_get_info(self, app_info: dict): - self._release_lock() self.finish_action() self.change_update_state() dialog_info = InfoDialog(app_info, self.table_apps.get_selected_app_icon(), self.locale_keys, self.table_apps.get_selected_app().model.get_type(), self.screen_size) dialog_info.exec_() def _finish_get_history(self, app: dict): - self._release_lock() self.finish_action() self.change_update_state() @@ -641,7 +596,7 @@ class ManageWindow(QWidget): word = self.input_search.text().strip() - if word and self._acquire_lock(): + if word: self._handle_console_option(False) self.ref_checkbox_only_apps.setVisible(False) self.ref_checkbox_updates.setVisible(False) @@ -651,34 +606,30 @@ class ManageWindow(QWidget): self.thread_search.start() def _finish_search(self, apps_found: List[Application]): - self._release_lock() self.finish_action() - self.update_apps(apps_found) + self.ref_bt_upgrade.setVisible(False) + self.update_apps(apps_found, update_check_enabled=False) def install_app(self, app: ApplicationView): - if self._acquire_lock(): + pwd = None + requires_root = self.manager.requires_root('install', self.table_apps.get_selected_app().model) - pwd = None - requires_root = self.manager.requires_root('install', self.table_apps.get_selected_app().model) + if not is_root() and requires_root: + pwd, ok = ask_root_password(self.locale_keys) - if not is_root() and requires_root: - pwd, ok = ask_root_password(self.locale_keys) + if not ok: + return - if not ok: - self._release_lock() - return + self._handle_console_option(True) + self._begin_action('{} {}'.format(self.locale_keys['manage_window.status.installing'], app.model.base_data.name)) - self._handle_console_option(True) - self._begin_action('{} {}'.format(self.locale_keys['manage_window.status.installing'], app.model.base_data.name)) - - self.thread_install.app = app - self.thread_install.root_password = pwd - self.thread_install.start() + self.thread_install.app = app + self.thread_install.root_password = pwd + self.thread_install.start() def _finish_install(self, success: bool): self.input_search.setText('') self.finish_action() - self._release_lock() if success: if self._can_notify_user():