From c2e59ba75768572b31f5b419cddbe1549494a57c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Moreira?= Date: Wed, 26 Jun 2019 15:52:26 -0300 Subject: [PATCH] Retrieving app information and history --- CHANGELOG.md | 1 + fpakman/core/flatpak.py | 51 +++++-- fpakman/core/system.py | 4 +- fpakman/resources/img/history.svg | 218 ++++++++++++++++++++++++++++++ fpakman/resources/img/info.svg | 154 +++++++++++++++++++++ fpakman/resources/locale/en | 32 ++++- fpakman/resources/locale/es | 36 +++-- fpakman/resources/locale/pt | 34 +++-- fpakman/view/qt/apps_table.py | 40 ++++-- fpakman/view/qt/history.py | 52 +++++++ fpakman/view/qt/info.py | 34 +++++ fpakman/view/qt/window.py | 107 ++++++++++++--- 12 files changed, 694 insertions(+), 69 deletions(-) create mode 100755 fpakman/resources/img/history.svg create mode 100755 fpakman/resources/img/info.svg create mode 100644 fpakman/view/qt/history.py create mode 100644 fpakman/view/qt/info.py diff --git a/CHANGELOG.md b/CHANGELOG.md index d224c420..987cfb0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [0.3.0] ### Features +- Allows to retrieve app information and history by right clicking it. - Allows app uninstall and downgrade by right clicking it. ### Improvements diff --git a/fpakman/core/flatpak.py b/fpakman/core/flatpak.py index 9933eea2..f8ba10be 100755 --- a/fpakman/core/flatpak.py +++ b/fpakman/core/flatpak.py @@ -4,6 +4,8 @@ from typing import List from fpakman.core import system +BASE_CMD = 'flatpak' + def app_str_to_json(line: str, version: str) -> dict: @@ -39,22 +41,24 @@ def app_str_to_json(line: str, version: str) -> dict: return app -def get_app_info_fields(app_id: str, branch: str, fields: List[str], check_runtime: bool = False): +def get_app_info_fields(app_id: str, branch: str, fields: List[str] = [], check_runtime: bool = False): info = re.findall(r'\w+:\s.+', get_app_info(app_id, branch)) data = {} fields_to_retrieve = len(fields) + (1 if check_runtime and 'ref' not in fields else 0) for field in info: - if fields_to_retrieve == 0: + if fields and fields_to_retrieve == 0: break field_val = field.split(':') field_name = field_val[0].lower() - if field_name in fields or (check_runtime and field_name == 'ref'): + if not fields or field_name in fields or (check_runtime and field_name == 'ref'): data[field_name] = field_val[1].strip() - fields_to_retrieve -= 1 + + if fields: + fields_to_retrieve -= 1 if check_runtime and field_name == 'ref': data['runtime'] = data['ref'].startswith('runtime/') @@ -63,16 +67,16 @@ def get_app_info_fields(app_id: str, branch: str, fields: List[str], check_runti def get_version(): - res = system.run_cmd('flatpak --version') + res = system.run_cmd('{} --version'.format(BASE_CMD)) return res.split(' ')[1].strip() if res else None def get_app_info(app_id: str, branch: str): - return system.run_cmd('flatpak info {} {}'.format(app_id, branch)) + return system.run_cmd('{} info {} {}'.format(BASE_CMD, app_id, branch)) def list_installed() -> List[dict]: - apps_str = system.run_cmd('flatpak list') + apps_str = system.run_cmd('{} list'.format(BASE_CMD)) if apps_str: version = get_version() @@ -83,7 +87,7 @@ def list_installed() -> List[dict]: def update(app_ref: str) -> bool: - return bool(system.run_cmd('flatpak update -y ' + app_ref)) + return bool(system.run_cmd('{} update -y {}'.format(BASE_CMD, app_ref))) def update_and_stream(app_ref: str): @@ -92,7 +96,7 @@ def update_and_stream(app_ref: str): :param app_ref: :return: """ - return system.stream_cmd(['flatpak', 'update', '-y', app_ref]) + return system.stream_cmd([BASE_CMD, 'update', '-y', app_ref]) def uninstall_and_stream(app_ref: str): @@ -101,11 +105,11 @@ def uninstall_and_stream(app_ref: str): :param app_ref: :return: """ - return system.stream_cmd(['flatpak', 'uninstall', app_ref, '-y']) + return system.stream_cmd([BASE_CMD, 'uninstall', app_ref, '-y']) def list_updates_as_str(): - return system.run_cmd('flatpak update', ignore_return_code=True) + return system.run_cmd('{} update'.format(BASE_CMD), ignore_return_code=True) def downgrade_and_stream(app_ref: str, commit: str, root_password: str): @@ -114,12 +118,31 @@ def downgrade_and_stream(app_ref: str, commit: str, root_password: str): if root_password is not None: downgrade_cmd.extend(['sudo', '-S']) - pwdin = subprocess.Popen(['echo', root_password], stdout=subprocess.PIPE).stdout + pwdin = system.stream_cmd(['echo', root_password]) - downgrade_cmd.extend(['flatpak', 'update', '--commit={}'.format(commit), app_ref, '-y']) + downgrade_cmd.extend([BASE_CMD, 'update', '--commit={}'.format(commit), app_ref, '-y']) return subprocess.Popen(downgrade_cmd, stdin=pwdin, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout def get_app_commits(app_ref: str, origin: str) -> List[str]: - log = system.run_cmd('flatpak remote-info --log {} {}'.format(origin, app_ref)) + log = system.run_cmd('{} remote-info --log {} {}'.format(BASE_CMD, origin, app_ref)) return re.findall(r'Commit+:\s(.+)', log) + + +def get_app_commits_data(app_ref: str, origin: str) -> List[dict]: + log = system.run_cmd('{} remote-info --log {} {}'.format(BASE_CMD, origin, app_ref)) + + res = re.findall(r'(Commit|Subject|Date):\s(.+)', log) + + commits = [] + + commit = {} + + for idx, data in enumerate(res): + commit[data[0].strip().lower()] = data[1].strip() + + if (idx + 1) % 3 == 0: + commits.append(commit) + commit = {} + + return commits diff --git a/fpakman/core/system.py b/fpakman/core/system.py index ddd5edfa..a7b1715b 100644 --- a/fpakman/core/system.py +++ b/fpakman/core/system.py @@ -3,9 +3,9 @@ from typing import List def run_cmd(cmd: str, expected_code: int = 0, ignore_return_code: bool = False) -> str: - res = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE) + res = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, env={'LANG': 'en'}) return res.stdout.decode() if ignore_return_code or res.returncode == expected_code else None def stream_cmd(cmd: List[str]): - return subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout + return subprocess.Popen(cmd, stdout=subprocess.PIPE, env={'LANG': 'en'}).stdout diff --git a/fpakman/resources/img/history.svg b/fpakman/resources/img/history.svg new file mode 100755 index 00000000..e1f00f18 --- /dev/null +++ b/fpakman/resources/img/history.svg @@ -0,0 +1,218 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fpakman/resources/img/info.svg b/fpakman/resources/img/info.svg new file mode 100755 index 00000000..7983485e --- /dev/null +++ b/fpakman/resources/img/info.svg @@ -0,0 +1,154 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fpakman/resources/locale/en b/fpakman/resources/locale/en index 3c1c96a5..b2a4787b 100644 --- a/fpakman/resources/locale/en +++ b/fpakman/resources/locale/en @@ -1,12 +1,8 @@ manage_window.title=Flatpak Application Manager -manage_window.columns.name=Name -manage_window.columns.version=Version manage_window.columns.latest_version=Latest Version -manage_window.columns.branch=Branch -manage_window.columns.arch=Arch -manage_window.columns.ref=Ref -manage_window.columns.origin=Origin manage_window.columns.update=Upgrade ? +manage_window.apps_table.row.actions.info=Information +manage_window.apps_table.row.actions.history=History manage_window.apps_table.row.actions.uninstall=Uninstall manage_window.apps_table.row.actions.uninstall.popup.title=Uninstall manage_window.apps_table.row.actions.uninstall.popup.body=Remove {} ? @@ -18,6 +14,8 @@ manage_window.status.refreshing=Refreshing manage_window.status.upgrading=Upgrading manage_window.status.uninstalling=Uninstalling manage_window.status.downgrading=Downgrading +manage_window.status.info=Retrieving information +manage_window.status.history=Retrieving history manage_window.bt.refresh.tooltip=Reload the data about installed applications manage_window.bt.upgrade.tooltip=Upgrade all selected applications popup.flatpak_not_installed.title=Error @@ -28,9 +26,29 @@ popup.root.bad_password.title=Error popup.root.bad_password.body=Wrong password popup.downgrade.impossible.title=Impossible to downgrade popup.downgrade.impossible.body=The app is in its first version +popup.history.title=History +popup.history.selected.tooltip=Current version popup.button.yes=Yes popup.button.no=No popup.button.cancel=Cancel tray.action.manage=Manage applications tray.action.exit=Exit -notification.new_updates=Updates found \ No newline at end of file +notification.new_updates=Updates found +flatpak.info.arch=arch +flatpak.info.branch=branch +flatpak.info.collection=collection +flatpak.info.commit=commit +flatpak.info.date=date +flatpak.info.id=id +flatpak.info.installation=installation +flatpak.info.installed=installed +flatpak.info.license=license +flatpak.info.name=name +flatpak.info.origin=origin +flatpak.info.parent=parent +flatpak.info.ref=ref +flatpak.info.runtime=runtime +flatpak.info.sdk=sdk +flatpak.info.subject=subject +flatpak.info.type=type +flatpak.info.version=version \ No newline at end of file diff --git a/fpakman/resources/locale/es b/fpakman/resources/locale/es index ad3da9ff..e4c897fb 100644 --- a/fpakman/resources/locale/es +++ b/fpakman/resources/locale/es @@ -1,23 +1,21 @@ manage_window.title=Administrador de Aplicativos Flatpak -manage_window.columns.name=Nombre -manage_window.columns.version=Versión manage_window.columns.latest_version=Ultima Versión -manage_window.columns.branch=Rama -manage_window.columns.arch=Arch -manage_window.columns.ref=Ref -manage_window.columns.origin=Origen -manage_window.columns.update=¿Actualizar? +manage_window.columns.update=Actualizar ? +manage_window.apps_table.row.actions.info=Información +manage_window.apps_table.row.actions.history=Historia manage_window.apps_table.row.actions.uninstall=Desinstalar manage_window.apps_table.row.actions.uninstall.popup.title=Desinstalación manage_window.apps_table.row.actions.uninstall.popup.body=¿Eliminar {}? manage_window.apps_table.row.actions.downgrade=Revertir versión manage_window.apps_table.row.actions.downgrade.popup.body=¿Realmente quieres revertir la versión actual de {}? -manage_window.checkbox.only_apps=Apps +manage_window.checkbox.only_apps=Aplicativos manage_window.label.updates=Actualizaciones manage_window.status.refreshing=Recargando manage_window.status.upgrading=Actualizando manage_window.status.uninstalling=Desinstalando manage_window.status.downgrading=Revirtiendo +manage_window.status.info=Obteniendo información +manage_window.status.history=Obteniendo la historia manage_window.bt.refresh.tooltip=Recarga los datos sobre los aplicativos instalados manage_window.bt.upgrade.tooltip=Actualiza todos los aplicativos seleccionados popup.flatpak_not_installed.title=Error @@ -28,9 +26,29 @@ popup.root.bad_password.title=Error popup.root.bad_password.body=Contraseña incorrecta popup.downgrade.impossible.title=Imposible revertir la versión popup.downgrade.impossible.body=El aplicativo está en su primera versión +popup.history.title=Historia +popup.history.selected.tooltip=Versión actual popup.button.yes=Sí popup.button.no=No popup.button.cancel=Cancelar tray.action.manage=Administrar aplicativos tray.action.exit=Salir -notification.new_updates=Actualizaciones encontradas \ No newline at end of file +notification.new_updates=Actualizaciones encontradas +flatpak.info.arch=arquitectura +flatpak.info.branch=rama +flatpak.info.collection=colección +flatpak.info.commit=commit +flatpak.info.date=fecha +flatpak.info.id=id +flatpak.info.installation=instalación +flatpak.info.installed=instalado +flatpak.info.license=licencia +flatpak.info.name=nombre +flatpak.info.origin=origen +flatpak.info.parent=padre +flatpak.info.ref=ref +flatpak.info.runtime=runtime +flatpak.info.sdk=sdk +flatpak.info.subject=tema +flatpak.info.type=tipo +flatpak.info.version=versión \ No newline at end of file diff --git a/fpakman/resources/locale/pt b/fpakman/resources/locale/pt index d917c4d2..5775be5e 100644 --- a/fpakman/resources/locale/pt +++ b/fpakman/resources/locale/pt @@ -1,23 +1,21 @@ manage_window.title=Gerenciador de Aplicativos Flatpak -manage_window.columns.name=Nome -manage_window.columns.version=Versão manage_window.columns.latest_version=Última Versão -manage_window.columns.branch=Ramo -manage_window.columns.arch=Arch -manage_window.columns.ref=Ref -manage_window.columns.origin=Origem manage_window.columns.update=Atualizar ? +manage_window.apps_table.row.actions.info=Informação +manage_window.apps_table.row.actions.history=Histórico manage_window.apps_table.row.actions.uninstall=Desinstalar manage_window.apps_table.row.actions.uninstall.popup.title=Desinstalação manage_window.apps_table.row.actions.uninstall.popup.body=Remover {}? manage_window.apps_table.row.actions.downgrade=Reverter versão manage_window.apps_table.row.actions.downgrade.popup.body=Você realmente quer reverter a versão atual de {} ? -manage_window.checkbox.only_apps=Apps +manage_window.checkbox.only_apps=Aplicativos manage_window.label.updates=Atualizações manage_window.status.refreshing=Recarregando manage_window.status.upgrading=Atualizando manage_window.status.uninstalling=Desinstalando manage_window.status.downgrading=Revertendo +manage_window.status.info=Obtendo informação +manage_window.status.history=Obtendo histórico manage_window.bt.refresh.tooltip=Recarrega os dados sobre os aplicativos instalados manage_window.bt.upgrade.tooltip=Atualiza todos os aplicativos selecionados popup.flatpak_not_installed.title=Erro @@ -28,9 +26,29 @@ popup.root.bad_password.title=Erro popup.root.bad_password.body=Senha incorreta popup.downgrade.impossible.title=Impossível reverter a versão popup.downgrade.impossible.body=O aplicativo está na sua primeira versão +popup.history.title=Histórico +popup.history.selected.tooltip=Versão atual popup.button.yes=Sim popup.button.no=Não popup.button.cancel=Cancelar tray.action.manage=Gerenciar aplicativos tray.action.exit=Sair -notification.new_updates=Atualizações encontradas \ No newline at end of file +notification.new_updates=Atualizações encontradas +flatpak.info.arch=arquitetura +flatpak.info.branch=ramo +flatpak.info.collection=coleção +flatpak.info.commit=commit +flatpak.info.date=data +flatpak.info.id=id +flatpak.info.installation=instalação +flatpak.info.installed=instalado +flatpak.info.license=licença +flatpak.info.name=nome +flatpak.info.origin=origem +flatpak.info.parent=pai +flatpak.info.ref=ref +flatpak.info.runtime=runtime +flatpak.info.sdk=sdk +flatpak.info.subject=assunto +flatpak.info.type=tipo +flatpak.info.version=versão \ No newline at end of file diff --git a/fpakman/view/qt/apps_table.py b/fpakman/view/qt/apps_table.py index 6478f64e..00b54437 100644 --- a/fpakman/view/qt/apps_table.py +++ b/fpakman/view/qt/apps_table.py @@ -1,12 +1,13 @@ +import json from typing import List -from PyQt5.QtCore import Qt, QUrl +from PyQt5.QtCore import Qt, QUrl, QThread, pyqtSignal from PyQt5.QtGui import QPixmap, QIcon, QColor, QCursor from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager from PyQt5.QtWidgets import QTableWidget, QTableView, QMenu, QAction, QTableWidgetItem, QToolButton, QWidget, \ - QMessageBox, QHeaderView + QMessageBox, QHeaderView, QDialog, QLineEdit, QVBoxLayout, QPlainTextEdit -from fpakman.core import resource +from fpakman.core import resource, flatpak from fpakman.core.controller import FlatpakController from fpakman.view.qt import dialog @@ -48,8 +49,6 @@ class AppsTable(QTableWidget): self.setHorizontalHeaderLabels(columns) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.icon_flathub = QIcon(resource.get_path('img/flathub_45.svg')) - self.icon_uninstall = QIcon(resource.get_path('img/uninstall.svg')) - self.icon_downgrade = QIcon(resource.get_path('img/downgrade.svg')) self.network_man = QNetworkAccessManager() self.network_man.finished.connect(self._load_icon) @@ -59,28 +58,41 @@ class AppsTable(QTableWidget): def contextMenuEvent(self, QContextMenuEvent): # selected row right click event menu_row = QMenu() + action_info = QAction(self.parent.locale_keys["manage_window.apps_table.row.actions.info"]) + action_info.setIcon(QIcon(resource.get_path('img/info.svg'))) + action_info.triggered.connect(self._get_app_info) + menu_row.addAction(action_info) + + action_history = QAction(self.parent.locale_keys["manage_window.apps_table.row.actions.history"]) + action_history.setIcon(QIcon(resource.get_path('img/history.svg'))) + action_history.triggered.connect(self._get_app_history) + menu_row.addAction(action_history) + action_uninstall = QAction(self.parent.locale_keys["manage_window.apps_table.row.actions.uninstall"]) - action_uninstall.setIcon(self.icon_uninstall) + action_uninstall.setIcon(QIcon(resource.get_path('img/uninstall.svg'))) action_uninstall.triggered.connect(self._uninstall_app) menu_row.addAction(action_uninstall) - app = self._get_selected_app() + app = self.get_selected_app() if not app['model']['runtime']: # downgrade only allowed for apps action_downgrade = QAction(self.parent.locale_keys["manage_window.apps_table.row.actions.downgrade"]) action_downgrade.triggered.connect(self._downgrade_app) - action_downgrade.setIcon(self.icon_downgrade) + action_downgrade.setIcon(QIcon(resource.get_path('img/downgrade.svg'))) menu_row.addAction(action_downgrade) menu_row.adjustSize() menu_row.popup(QCursor.pos()) menu_row.exec_() - def _get_selected_app(self): + def get_selected_app(self): return self.parent.apps[self.currentRow()] + def get_selected_app_icon(self): + return self.item(self.currentRow(), 0).icon() + def _uninstall_app(self): - selected_app = self._get_selected_app() + selected_app = self.get_selected_app() if dialog.ask_confirmation(title=self.parent.locale_keys['manage_window.apps_table.row.actions.uninstall.popup.title'], body=self.parent.locale_keys['manage_window.apps_table.row.actions.uninstall.popup.body'].format(selected_app['model']['name']), @@ -88,13 +100,19 @@ class AppsTable(QTableWidget): self.parent.uninstall_app(selected_app['model']['ref']) def _downgrade_app(self): - selected_app = self._get_selected_app() + selected_app = self.get_selected_app() if dialog.ask_confirmation(title=self.parent.locale_keys['manage_window.apps_table.row.actions.downgrade'], body=self.parent.locale_keys['manage_window.apps_table.row.actions.downgrade.popup.body'].format(selected_app['model']['name']), locale_keys=self.parent.locale_keys): self.parent.downgrade_app(selected_app['model']['ref']) + def _get_app_info(self): + self.parent.get_app_info(self.get_selected_app()) + + def _get_app_history(self): + self.parent.get_app_history(self.get_selected_app()) + def _load_icon(self, http_response): icon_url = http_response.url().toString() pixmap = QPixmap() diff --git a/fpakman/view/qt/history.py b/fpakman/view/qt/history.py new file mode 100644 index 00000000..5282fe97 --- /dev/null +++ b/fpakman/view/qt/history.py @@ -0,0 +1,52 @@ +import operator +from functools import reduce + +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QIcon +from PyQt5.QtWidgets import QDialog, QVBoxLayout, QTableWidget, QTableWidgetItem, QHeaderView + + +class HistoryDialog(QDialog): + + def __init__(self, app: dict, app_icon: QIcon, locale_keys: dict): + super(HistoryDialog, self).__init__() + + self.setWindowTitle('{} - {} '.format(locale_keys['popup.history.title'], app['model']['name'])) + self.setWindowIcon(app_icon) + + layout = QVBoxLayout() + self.setLayout(layout) + + table_history = QTableWidget() + table_history.setFocusPolicy(Qt.NoFocus) + table_history.setShowGrid(False) + table_history.verticalHeader().setVisible(False) + table_history.setAlternatingRowColors(True) + + table_history.setColumnCount(len(app['commits'][0])) + table_history.setRowCount(len(app['commits'])) + table_history.setHorizontalHeaderLabels([locale_keys['flatpak.info.' + key].capitalize() for key in sorted(app['commits'][0].keys())]) + + for row, commit in enumerate(app['commits']): + + current_app_commit = app['model']['commit'] == commit['commit'] + + for col, key in enumerate(sorted(commit.keys())): + item = QTableWidgetItem() + item.setText(commit[key]) + item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) + + if current_app_commit: + item.setBackground(Qt.darkYellow) + item.setToolTip(locale_keys['popup.history.selected.tooltip']) + + table_history.setItem(row, col, item) + + layout.addWidget(table_history) + + header_horizontal = table_history.horizontalHeader() + for i in range(0, table_history.columnCount()): + header_horizontal.setSectionResizeMode(i, QHeaderView.Stretch) + + new_width = reduce(operator.add, [table_history.columnWidth(i) for i in range(table_history.columnCount())]) + self.resize(new_width, table_history.height()) diff --git a/fpakman/view/qt/info.py b/fpakman/view/qt/info.py new file mode 100644 index 00000000..db32fb30 --- /dev/null +++ b/fpakman/view/qt/info.py @@ -0,0 +1,34 @@ +from PyQt5.QtGui import QIcon +from PyQt5.QtWidgets import QDialog, QVBoxLayout, QFormLayout, QGroupBox, \ + QLineEdit, QLabel + + +class InfoDialog(QDialog): + + def __init__(self, app: dict, app_icon: QIcon, locale_keys: dict): + super(InfoDialog, self).__init__() + self.setWindowTitle(app['name']) + self.setWindowIcon(app_icon) + layout = QVBoxLayout() + self.setLayout(layout) + + gbox_info_layout = QFormLayout() + gbox_info = QGroupBox() + gbox_info.setLayout(gbox_info_layout) + layout.addWidget(gbox_info) + + for attr in sorted(app.keys()): + + if attr != 'name': + text = QLineEdit() + text.setText(app[attr]) + text.setStyleSheet("width: 400px") + text.setReadOnly(True) + text.setCursorPosition(0) + + label = QLabel("{}: ".format(locale_keys.get('flatpak.info.' + attr, attr)).capitalize()) + label.setStyleSheet("font-weight: bold") + + gbox_info_layout.addRow(label, text) + + self.adjustSize() diff --git a/fpakman/view/qt/window.py b/fpakman/view/qt/window.py index b6b09a27..137d9606 100755 --- a/fpakman/view/qt/window.py +++ b/fpakman/view/qt/window.py @@ -1,19 +1,22 @@ +import json import operator from functools import reduce from threading import Lock from typing import List -from PyQt5.QtCore import QThread, pyqtSignal, QEvent +from PyQt5.QtCore import QThread, pyqtSignal, QEvent, Qt from PyQt5.QtGui import QIcon, QWindowStateChangeEvent from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QCheckBox, QHeaderView, QToolButton, QToolBar, \ - QSizePolicy, QLabel, QMessageBox, QPlainTextEdit -from fpakman.core.model import FlatpakManager, ImpossibleDowngradeException + QSizePolicy, QLabel, QPlainTextEdit, QDialog, QGroupBox, QFormLayout, QLineEdit, QTableWidget, QTableWidgetItem from fpakman import __version__ -from fpakman.core import resource +from fpakman.core import resource, flatpak from fpakman.core.controller import FlatpakController +from fpakman.core.model import FlatpakManager, ImpossibleDowngradeException from fpakman.view.qt import dialog from fpakman.view.qt.apps_table import AppsTable +from fpakman.view.qt.history import HistoryDialog +from fpakman.view.qt.info import InfoDialog from fpakman.view.qt.root import is_root, ask_root_password @@ -21,17 +24,17 @@ class ManageWindow(QWidget): __BASE_HEIGHT__ = 400 - def __init__(self, locale_keys: dict, controller: FlatpakController, manager: FlatpakManager, tray_icon = None): + def __init__(self, locale_keys: dict, controller: FlatpakController, manager: FlatpakManager, tray_icon=None): super(ManageWindow, self).__init__() self.locale_keys = locale_keys - self.column_names = [locale_keys['manage_window.columns.name'], - locale_keys['manage_window.columns.version'], - locale_keys['manage_window.columns.latest_version'], - locale_keys['manage_window.columns.branch'], - locale_keys['manage_window.columns.arch'], - locale_keys['manage_window.columns.ref'], - locale_keys['manage_window.columns.origin'], - locale_keys['manage_window.columns.update']] + self.column_names = [locale_keys[key].capitalize() for key in ['flatpak.info.name', + 'flatpak.info.version', + 'manage_window.columns.latest_version', + 'flatpak.info.branch', + 'flatpak.info.arch', + 'flatpak.info.ref', + 'flatpak.info.origin', + 'manage_window.columns.update']] self.controller = controller self.manager = manager self.tray_icon = tray_icon @@ -112,6 +115,12 @@ class ManageWindow(QWidget): self.thread_downgrade.signal_output.connect(self._update_action_output) self.thread_downgrade.signal_finished.connect(self._finish_downgrade) + self.thread_get_info = GetAppInfo() + self.thread_get_info.signal_finished.connect(self._finish_get_info) + + self.thread_get_history = GetAppHistory() + self.thread_get_history.signal_finished.connect(self._finish_get_history) + self.toolbar_bottom = QToolBar() self.label_updates = QLabel('') self.toolbar_bottom.addWidget(self.label_updates) @@ -174,7 +183,7 @@ class ManageWindow(QWidget): if self._acquire_lock(): self._check_flatpak_installed() - self._begin_action(self.locale_keys['manage_window.status.refreshing'] + '...') + self._begin_action(self.locale_keys['manage_window.status.refreshing']) if clear_output: self.textarea_output.clear() @@ -194,7 +203,7 @@ class ManageWindow(QWidget): if self._acquire_lock(): self.textarea_output.clear() self.textarea_output.setVisible(True) - self._begin_action(self.locale_keys['manage_window.status.uninstalling'] + '...') + self._begin_action(self.locale_keys['manage_window.status.uninstalling']) self.thread_uninstall.app_ref = app_ref self.thread_uninstall.start() @@ -303,7 +312,7 @@ class ManageWindow(QWidget): self.textarea_output.clear() self.textarea_output.setVisible(True) - self._begin_action(self.locale_keys['manage_window.status.upgrading'] + '...') + self._begin_action(self.locale_keys['manage_window.status.upgrading']) self.thread_update.refs_to_update = to_update self.thread_update.start() @@ -316,7 +325,7 @@ class ManageWindow(QWidget): self.textarea_output.appendPlainText(output) def _begin_action(self, action_label: str): - self.label_status.setText(action_label) + self.label_status.setText(action_label + "...") self.bt_upgrade.setEnabled(False) self.bt_refresh.setEnabled(False) self.checkbox_only_apps.setEnabled(False) @@ -345,12 +354,44 @@ class ManageWindow(QWidget): self.textarea_output.clear() self.textarea_output.setVisible(True) - self._begin_action(self.locale_keys['manage_window.status.downgrading'] + '...') + self._begin_action(self.locale_keys['manage_window.status.downgrading']) self.thread_downgrade.app_ref = app_ref self.thread_downgrade.root_password = pwd self.thread_downgrade.start() + def get_app_info(self, app: dict): + + if self._acquire_lock(): + self.textarea_output.clear() + self.textarea_output.setVisible(False) + self._begin_action(self.locale_keys['manage_window.status.info']) + + self.thread_get_info.app = app + self.thread_get_info.start() + + def get_app_history(self, app: dict): + if self._acquire_lock(): + self.textarea_output.clear() + self.textarea_output.setVisible(False) + self._begin_action(self.locale_keys['manage_window.status.history']) + + 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() + dialog_info = InfoDialog(app_info, self.table_apps.get_selected_app_icon(), self.locale_keys) + dialog_info.exec_() + + def _finish_get_history(self, app: dict): + self._release_lock() + self.finish_action() + + dialog_history = HistoryDialog(app, self.table_apps.get_selected_app_icon(), self.locale_keys) + dialog_history.exec_() + # Threaded actions class UpdateSelectedApps(QThread): @@ -433,3 +474,33 @@ class DowngradeApp(QThread): self.app_ref = None self.root_password = None self.signal_finished.emit() + + +class GetAppInfo(QThread): + signal_finished = pyqtSignal(dict) + + def __init__(self): + super(GetAppInfo, self).__init__() + self.app = None + + def run(self): + if self.app: + app_info = flatpak.get_app_info_fields(self.app['model']['id'], self.app['model']['branch']) + app_info['name'] = self.app['model']['name'] + app_info['type'] = 'runtime' if self.app['model']['runtime'] else 'app' + self.signal_finished.emit(app_info) + self.app = None + + +class GetAppHistory(QThread): + signal_finished = pyqtSignal(dict) + + def __init__(self): + super(GetAppHistory, self).__init__() + self.app = None + + def run(self): + if self.app: + commits = flatpak.get_app_commits_data(self.app['model']['ref'], self.app['model']['origin']) + self.signal_finished.emit({'model': self.app['model'], 'commits': commits}) + self.app = None