[appimage] improvement -> manual file installation: trying to auto-fill the 'Name' and 'Version' fields

This commit is contained in:
Vinicius Moreira
2020-08-11 15:38:30 -03:00
parent 244d48f18a
commit ae721f6eea
4 changed files with 78 additions and 15 deletions

View File

@@ -7,7 +7,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [0.9.7] 2020 ## [0.9.7] 2020
### Improvements ### Improvements
- AppImage - AppImage
- Manual file installation default search path set to '~/Downloads' - Manual file installation:
- default search path set to '~/Downloads'
- trying to auto-fill the 'Name' and 'Version' fields
- Arch - Arch
- upgrade summary: displaying the reason a given package must be installed - upgrade summary: displaying the reason a given package must be installed
<p align="center"> <p align="center">

View File

@@ -1,6 +1,6 @@
from abc import ABC from abc import ABC
from enum import Enum from enum import Enum
from typing import List, Set from typing import List, Set, Optional
class MessageType: class MessageType:
@@ -9,12 +9,22 @@ class MessageType:
ERROR = 2 ERROR = 2
class ViewObserver:
def on_change(self, change):
pass
class ViewComponent(ABC): class ViewComponent(ABC):
""" """
Represents a GUI component Represents a GUI component
""" """
def __init__(self, id_: str): def __init__(self, id_: str, observers: List[ViewObserver] = None):
self.id = id_ self.id = id_
self.observers = observers if observers else []
def add_observer(self, obs):
self.observers.append(obs)
class SpacerComponent(ViewComponent): class SpacerComponent(ViewComponent):
@@ -157,6 +167,14 @@ class TextInputComponent(ViewComponent):
else: else:
return '' return ''
def set_value(self, val: Optional[str], caller: object = None):
self.value = val
if self.observers:
for o in self.observers:
if caller != o:
o.on_change(val)
def get_int_value(self) -> int: def get_int_value(self) -> int:
if self.value is not None: if self.value is not None:
val = self.value.strip() if isinstance(self.value, str) else self.value val = self.value.strip() if isinstance(self.value, str) else self.value
@@ -191,6 +209,13 @@ class FileChooserComponent(ViewComponent):
self.max_width = max_width self.max_width = max_width
self.search_path = search_path self.search_path = search_path
def set_file_path(self, fpath: str):
self.file_path = fpath
if self.observers:
for o in self.observers:
o.on_change(self.file_path)
class TabComponent(ViewComponent): class TabComponent(ViewComponent):

View File

@@ -23,7 +23,7 @@ from bauh.api.abstract.handler import ProcessWatcher, TaskManager
from bauh.api.abstract.model import SoftwarePackage, PackageHistory, PackageUpdate, PackageSuggestion, \ from bauh.api.abstract.model import SoftwarePackage, PackageHistory, PackageUpdate, PackageSuggestion, \
SuggestionPriority, CustomSoftwareAction SuggestionPriority, CustomSoftwareAction
from bauh.api.abstract.view import MessageType, ViewComponent, FormComponent, InputOption, SingleSelectComponent, \ from bauh.api.abstract.view import MessageType, ViewComponent, FormComponent, InputOption, SingleSelectComponent, \
SelectViewType, TextInputComponent, PanelComponent, FileChooserComponent SelectViewType, TextInputComponent, PanelComponent, FileChooserComponent, ViewObserver
from bauh.commons import resource from bauh.commons import resource
from bauh.commons.config import save_config from bauh.commons.config import save_config
from bauh.commons.html import bold from bauh.commons.html import bold
@@ -42,6 +42,28 @@ DESKTOP_ENTRIES_PATH = '{}/.local/share/applications'.format(str(Path.home()))
RE_DESKTOP_EXEC = re.compile(r'Exec\s*=\s*.+\n') RE_DESKTOP_EXEC = re.compile(r'Exec\s*=\s*.+\n')
RE_DESKTOP_ICON = re.compile(r'Icon\s*=\s*.+\n') RE_DESKTOP_ICON = re.compile(r'Icon\s*=\s*.+\n')
RE_ICON_ENDS_WITH = re.compile(r'.+\.(png|svg)$') RE_ICON_ENDS_WITH = re.compile(r'.+\.(png|svg)$')
RE_APPIMAGE_NAME = re.compile(r'(.+)\.appimage', flags=re.IGNORECASE)
class ManualInstallationFileObserver(ViewObserver):
def __init__(self, name: TextInputComponent, version: TextInputComponent):
self.name = name
self.version = version
def on_change(self, file_path: str):
if file_path:
name_found = RE_APPIMAGE_NAME.findall(file_path.split('/')[-1])
if name_found:
name_split = name_found[0].split('-')
self.name.set_value(name_split[0].strip())
if len(name_split) > 1:
self.version.set_value(name_split[1].strip())
else:
self.name.set_value(None)
self.version.set_value(None)
class AppImageManager(SoftwareManager): class AppImageManager(SoftwareManager):
@@ -74,9 +96,13 @@ class AppImageManager(SoftwareManager):
if not os.path.isdir(default_path): if not os.path.isdir(default_path):
default_path = None default_path = None
file_chooser = FileChooserComponent(label=self.i18n['file'].capitalize(), allowed_extensions={'AppImage'}, search_path=default_path) file_chooser = FileChooserComponent(label=self.i18n['file'].capitalize(),
allowed_extensions={'AppImage'},
search_path=default_path)
input_name = TextInputComponent(label=self.i18n['name'].capitalize()) input_name = TextInputComponent(label=self.i18n['name'].capitalize())
input_version = TextInputComponent(label=self.i18n['version'].capitalize()) input_version = TextInputComponent(label=self.i18n['version'].capitalize())
file_chooser.observers.append(ManualInstallationFileObserver(input_name, input_version))
input_description = TextInputComponent(label=self.i18n['description'].capitalize()) input_description = TextInputComponent(label=self.i18n['description'].capitalize())
cat_ops = [InputOption(label=self.i18n['category.none'].capitalize(), value=0)] cat_ops = [InputOption(label=self.i18n['category.none'].capitalize(), value=0)]

View File

@@ -11,7 +11,7 @@ from PyQt5.QtWidgets import QRadioButton, QGroupBox, QCheckBox, QComboBox, QGrid
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, \
TwoStateButtonComponent, TextComponent, SpacerComponent, RangeInputComponent TwoStateButtonComponent, TextComponent, SpacerComponent, RangeInputComponent, ViewObserver
from bauh.view.qt import css from bauh.view.qt import css
from bauh.view.qt.colors import RED from bauh.view.qt.colors import RED
from bauh.view.util import resource from bauh.view.util import resource
@@ -428,6 +428,15 @@ class ComboSelectQt(QGroupBox):
self.layout().addWidget(FormComboBoxQt(model), 0, 1) self.layout().addWidget(FormComboBoxQt(model), 0, 1)
class QLineEditObserver(QLineEdit, ViewObserver):
def __init__(self, **kwargs):
super(QLineEditObserver, self).__init__(**kwargs)
def on_change(self, change: str):
self.setText(change if change is not None else '')
class TextInputQt(QGroupBox): class TextInputQt(QGroupBox):
def __init__(self, model: TextInputComponent): def __init__(self, model: TextInputComponent):
@@ -440,7 +449,7 @@ class TextInputQt(QGroupBox):
if self.model.max_width > 0: if self.model.max_width > 0:
self.setMaximumWidth(self.model.max_width) self.setMaximumWidth(self.model.max_width)
self.text_input = QLineEdit() self.text_input = QLineEditObserver()
if model.only_int: if model.only_int:
self.text_input.setValidator(QIntValidator()) self.text_input.setValidator(QIntValidator())
@@ -457,10 +466,11 @@ class TextInputQt(QGroupBox):
self.text_input.textChanged.connect(self._update_model) self.text_input.textChanged.connect(self._update_model)
self.model.observers.append(self.text_input)
self.layout().addWidget(self.text_input, 0, 1) self.layout().addWidget(self.text_input, 0, 1)
def _update_model(self, text: str): def _update_model(self, text: str):
self.model.value = text self.model.set_value(val=text, caller=self)
class MultipleSelectQt(QGroupBox): class MultipleSelectQt(QGroupBox):
@@ -754,7 +764,7 @@ class FormQt(QGroupBox):
return tip_icon return tip_icon
def _new_text_input(self, c: TextInputComponent) -> Tuple[QLabel, QLineEdit]: def _new_text_input(self, c: TextInputComponent) -> Tuple[QLabel, QLineEdit]:
line_edit = QLineEdit() line_edit = QLineEditObserver()
if c.only_int: if c.only_int:
line_edit.setValidator(QIntValidator()) line_edit.setValidator(QIntValidator())
@@ -773,9 +783,10 @@ class FormQt(QGroupBox):
line_edit.setEnabled(False) line_edit.setEnabled(False)
def update_model(text: str): def update_model(text: str):
c.value = text c.set_value(val=text, caller=line_edit)
line_edit.textChanged.connect(update_model) line_edit.textChanged.connect(update_model)
c.observers.append(line_edit)
label = QWidget() label = QWidget()
label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
@@ -819,7 +830,7 @@ class FormQt(QGroupBox):
return field_container return field_container
def _new_file_chooser(self, c: FileChooserComponent) -> Tuple[QLabel, QLineEdit]: def _new_file_chooser(self, c: FileChooserComponent) -> Tuple[QLabel, QLineEdit]:
chooser = QLineEdit() chooser = QLineEditObserver()
chooser.setReadOnly(True) chooser.setReadOnly(True)
if c.max_width > 0: if c.max_width > 0:
@@ -828,6 +839,7 @@ class FormQt(QGroupBox):
if c.file_path: if c.file_path:
chooser.setText(c.file_path) chooser.setText(c.file_path)
c.observers.append(chooser)
chooser.setPlaceholderText(self.i18n['view.components.file_chooser.placeholder']) chooser.setPlaceholderText(self.i18n['view.components.file_chooser.placeholder'])
def open_chooser(e): def open_chooser(e):
@@ -848,14 +860,12 @@ class FormQt(QGroupBox):
file_path, _ = QFileDialog.getOpenFileName(self, self.i18n['file_chooser.title'], cur_path, exts, options=options) file_path, _ = QFileDialog.getOpenFileName(self, self.i18n['file_chooser.title'], cur_path, exts, options=options)
if file_path: if file_path:
c.file_path = file_path c.set_file_path(file_path)
chooser.setText(file_path)
chooser.setCursorPosition(0) chooser.setCursorPosition(0)
def clean_path(): def clean_path():
c.file_path = None c.set_file_path(None)
chooser.setText('')
chooser.mousePressEvent = open_chooser chooser.mousePressEvent = open_chooser