appimage history | history panel can now be maximized

This commit is contained in:
Vinicius Moreira
2019-10-08 13:33:10 -03:00
parent 2e2c6bab90
commit 66a1e91f76
8 changed files with 71 additions and 27 deletions

View File

@@ -11,10 +11,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Improvements ### Improvements
- AUR: - AUR:
- Optional dependencies are not checked by default in their installation popup. - Optional dependencies are not checked by default in their installation popup.
- History panel can now me maximized, minimized and allows to copy column content.
- Minor UI improvements - Minor UI improvements
### AppImage support ### AppImage support
- Search, install, uninstall applications available in [AppImageHub](https://appimage.github.io) - Search, install, uninstall and retrieve history of applications available in [AppImageHub](https://appimage.github.io)
- Adds desktop entries (menu shortcuts) for the installed applications - Adds desktop entries (menu shortcuts) for the installed applications

View File

@@ -19,7 +19,9 @@ from bauh.commons.system import SystemProcess, new_subprocess, ProcessHandler, r
from bauh.gems.appimage import query, INSTALLATION_PATH from bauh.gems.appimage import query, INSTALLATION_PATH
from bauh.gems.appimage.model import AppImage from bauh.gems.appimage.model import AppImage
DB_PATH = '{}/{}'.format(HOME_PATH, '.local/share/bauh/appimage/appimage.db') DB_APPS_PATH = '{}/{}'.format(HOME_PATH, '.local/share/bauh/appimage/apps.db')
DB_RELEASES_PATH = '{}/{}'.format(HOME_PATH, '.local/share/bauh/appimage/releases.db')
DESKTOP_ENTRIES_PATH = '{}/.local/share/applications'.format(HOME_PATH) DESKTOP_ENTRIES_PATH = '{}/.local/share/applications'.format(HOME_PATH)
RE_DESKTOP_EXEC = re.compile(r'Exec\s*=\s*.+\n') RE_DESKTOP_EXEC = re.compile(r'Exec\s*=\s*.+\n')
@@ -39,18 +41,18 @@ class AppImageManager(SoftwareManager):
self.logger = context.logger self.logger = context.logger
self.file_downloader = context.file_downloader self.file_downloader = context.file_downloader
def _get_db_connection(self) -> sqlite3.Connection: def _get_db_connection(self, db_path: str) -> sqlite3.Connection:
if os.path.exists(DB_PATH): if os.path.exists(db_path):
return sqlite3.connect(DB_PATH) return sqlite3.connect(db_path)
def search(self, words: str, disk_loader: DiskCacheLoader, limit: int = -1) -> SearchResult: def search(self, words: str, disk_loader: DiskCacheLoader, limit: int = -1) -> SearchResult:
res = SearchResult([], [], 0) res = SearchResult([], [], 0)
connection = self._get_db_connection() connection = self._get_db_connection(DB_APPS_PATH)
if connection: if connection:
try: try:
cursor = connection.cursor() cursor = connection.cursor()
cursor.execute(query.SEARCH_BY_NAME_OR_DESCRIPTION.format(words, words)) cursor.execute(query.SEARCH_APPS_BY_NAME_OR_DESCRIPTION.format(words, words))
for l in cursor.fetchall(): for l in cursor.fetchall():
app = AppImage(*l) app = AppImage(*l)
@@ -58,7 +60,7 @@ class AppImageManager(SoftwareManager):
finally: finally:
connection.close() connection.close()
else: else:
self.logger.warning('Could not get a connection from the local database at {}'.format(DB_PATH)) self.logger.warning('Could not get a connection from the local database at {}'.format(DB_APPS_PATH))
res.total = len(res.installed) + len(res.new) res.total = len(res.installed) + len(res.new)
return res return res
@@ -111,8 +113,35 @@ class AppImageManager(SoftwareManager):
return pkg.get_data_to_cache() return pkg.get_data_to_cache()
def get_history(self, pkg: AppImage) -> PackageHistory: def get_history(self, pkg: AppImage) -> PackageHistory:
# TODO history = []
pass res = PackageHistory(pkg, history, -1)
connection = self._get_db_connection(DB_APPS_PATH)
if connection:
cursor = connection.cursor()
cursor.execute(query.FIND_APP_ID_BY_NAME_AND_GITHUB.format(pkg.name.lower(), pkg.github.lower()))
app_tuple = cursor.fetchone()
if not app_tuple:
raise Exception("Could not retrieve {} from the database {}".format(pkg, DB_APPS_PATH))
connection.close()
connection = self._get_db_connection(DB_RELEASES_PATH)
cursor = connection.cursor()
releases = cursor.execute(query.FIND_RELEASES_BY_APP_ID.format(app_tuple[0]))
if releases:
for idx, tup in enumerate(releases):
history.append({'0_version': tup[0], '1_published_at': tup[2], '2_url_download': tup[1]})
if res.pkg_status_idx == -1 and pkg.version == tup[0]:
res.pkg_status_idx = idx
return res
def _find_desktop_file(self, folder: str) -> str: def _find_desktop_file(self, folder: str) -> str:
for r, d, files in os.walk(folder): for r, d, files in os.walk(folder):

View File

@@ -4,7 +4,7 @@ from bauh.api.abstract.model import SoftwarePackage
from bauh.commons import resource from bauh.commons import resource
from bauh.gems.appimage import ROOT_DIR, INSTALLATION_PATH from bauh.gems.appimage import ROOT_DIR, INSTALLATION_PATH
CACHED_ATTRS = {'name', 'description', 'version', 'url_download', 'author', 'license', 'source', 'icon_path'} CACHED_ATTRS = {'name', 'description', 'version', 'url_download', 'author', 'license', 'source', 'icon_path', 'github'}
class AppImage(SoftwarePackage): class AppImage(SoftwarePackage):
@@ -22,12 +22,14 @@ class AppImage(SoftwarePackage):
self.icon_path = icon_path self.icon_path = icon_path
self.author = author self.author = author
def __repr__(self):
return "{} (name={}, github={})".format(self.__class__.__name__, self.name, self.github)
def can_be_installed(self): def can_be_installed(self):
return not self.installed and self.url_download return not self.installed and self.url_download
def has_history(self): def has_history(self):
# TODO return self.installed
return False
def has_info(self): def has_info(self):
return True return True

View File

@@ -1,5 +1,7 @@
ATTRS = ('name', 'description', 'github', 'source', 'version', 'url_download', 'url_icon', 'license', 'author') APP_ATTRS = ('name', 'description', 'github', 'source', 'version', 'url_download', 'url_icon', 'license', 'author')
RELEASE_ATTRS = ('version', 'url_download', 'published_at')
_SELECT_BASE = "SELECT {} FROM apps".format(','.join(ATTRS))
SEARCH_BY_NAME_OR_DESCRIPTION = _SELECT_BASE + " WHERE lower(name) LIKE '%{}%' or lower(description) LIKE '%{}%'" SEARCH_APPS_BY_NAME_OR_DESCRIPTION = "SELECT {} FROM apps".format(','.join(APP_ATTRS)) + " WHERE lower(name) LIKE '%{}%' or lower(description) LIKE '%{}%'"
FIND_APP_ID_BY_NAME_AND_GITHUB = "SELECT id FROM apps WHERE lower(name) = '{}' and lower(github) = '{}'"
FIND_RELEASES_BY_APP_ID = "SELECT {} FROM releases".format(','.join(RELEASE_ATTRS)) + " WHERE app_id = {} ORDER BY version desc"

View File

@@ -5,3 +5,6 @@ appimage.install.desktop_entry=Generating a menu shortcut
appimage.uninstall.error.remove_folder=Could not remove the application installation directory {} appimage.uninstall.error.remove_folder=Could not remove the application installation directory {}
appimage.info.url_download=File URL appimage.info.url_download=File URL
appimage.info.icon_path=icon appimage.info.icon_path=icon
appimage.history.0_version=version
appimage.history.1_published_at=date
appimage.history.2_url_download=File URL

View File

@@ -5,3 +5,6 @@ appimage.install.desktop_entry=Creando un atajo en el menú
appimage.uninstall.error.remove_folder=No se pudo eliminar el directorio de instalación de la aplicación {} appimage.uninstall.error.remove_folder=No se pudo eliminar el directorio de instalación de la aplicación {}
appimage.info.url_download=URL del archivo appimage.info.url_download=URL del archivo
appimage.info.icon_path=icono appimage.info.icon_path=icono
appimage.history.0_version=versión
appimage.history.1_published_at=fecha
appimage.history.2_url_download=URL del archivo

View File

@@ -5,3 +5,6 @@ appimage.install.desktop_entry=Criando um atalho no menu
appimage.uninstall.error.remove_folder=Não foi possível remover o diretóri ode instalação do aplicativo {} appimage.uninstall.error.remove_folder=Não foi possível remover o diretóri ode instalação do aplicativo {}
appimage.info.url_download=URL do arquivo appimage.info.url_download=URL do arquivo
appimage.info.icon_path=ícone appimage.info.icon_path=ícone
appimage.history.0_version=versão
appimage.history.1_published_at=data
appimage.history.2_url_download=URL do arquivo

View File

@@ -4,16 +4,18 @@ from functools import reduce
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtGui import QColor from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QTableWidget, QTableWidgetItem, QHeaderView from PyQt5.QtWidgets import QDialog, QVBoxLayout, QTableWidget, QTableWidgetItem, QHeaderView
from bauh.api.abstract.cache import MemoryCache from bauh.api.abstract.cache import MemoryCache
from bauh.api.abstract.model import PackageHistory from bauh.api.abstract.model import PackageHistory
class HistoryDialog(QDialog): class HistoryDialog(QDialog):
def __init__(self, history: PackageHistory, icon_cache: MemoryCache, locale_keys: dict): def __init__(self, history: PackageHistory, icon_cache: MemoryCache, i18n: dict):
super(HistoryDialog, self).__init__() super(HistoryDialog, self).__init__()
self.setWindowFlags(self.windowFlags() | Qt.WindowSystemMenuHint | Qt.WindowMinMaxButtonsHint)
self.setWindowTitle('{} - {} ({})'.format(locale_keys['popup.history.title'], history.pkg.name, history.pkg.get_type())) self.setWindowTitle('{} - {} ({})'.format(i18n['popup.history.title'], history.pkg.name, history.pkg.get_type()))
layout = QVBoxLayout() layout = QVBoxLayout()
self.setLayout(layout) self.setLayout(layout)
@@ -26,20 +28,19 @@ class HistoryDialog(QDialog):
table_history.setColumnCount(len(history.history[0])) table_history.setColumnCount(len(history.history[0]))
table_history.setRowCount(len(history.history)) table_history.setRowCount(len(history.history))
table_history.setHorizontalHeaderLabels([locale_keys.get(history.pkg.get_type() + '.history.' + key, key).capitalize() for key in sorted(history.history[0].keys())]) table_history.setHorizontalHeaderLabels([i18n.get(history.pkg.get_type().lower() + '.history.' + key, i18n.get(key, key)).capitalize() for key in sorted(history.history[0].keys())])
for row, commit in enumerate(history.history): for row, data in enumerate(history.history):
current_status = history.pkg_status_idx == row current_status = history.pkg_status_idx == row
for col, key in enumerate(sorted(commit.keys())): for col, key in enumerate(sorted(data.keys())):
item = QTableWidgetItem() item = QTableWidgetItem()
item.setText(str(commit[key])) item.setText(str(data[key]))
item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
if current_status: if current_status:
item.setBackground(QColor('#ffbf00' if row != 0 else '#32CD32')) item.setBackground(QColor('#ffbf00' if row != 0 else '#32CD32'))
tip = '{}. {}.'.format(locale_keys['popup.history.selected.tooltip'], locale_keys['version.{}'.format('updated'if row == 0 else 'outdated')].capitalize()) tip = '{}. {}.'.format(i18n['popup.history.selected.tooltip'], i18n['version.{}'.format('updated'if row == 0 else 'outdated')].capitalize())
item.setToolTip(tip) item.setToolTip(tip)