mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-07 05:54:15 +02:00
[appimage] improvement -> manual file installation: trying to auto-fill the 'Name' and 'Version' fields
This commit is contained in:
@@ -7,7 +7,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
## [0.9.7] 2020
|
||||
### Improvements
|
||||
- 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
|
||||
- upgrade summary: displaying the reason a given package must be installed
|
||||
<p align="center">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from abc import ABC
|
||||
from enum import Enum
|
||||
from typing import List, Set
|
||||
from typing import List, Set, Optional
|
||||
|
||||
|
||||
class MessageType:
|
||||
@@ -9,12 +9,22 @@ class MessageType:
|
||||
ERROR = 2
|
||||
|
||||
|
||||
class ViewObserver:
|
||||
|
||||
def on_change(self, change):
|
||||
pass
|
||||
|
||||
|
||||
class ViewComponent(ABC):
|
||||
"""
|
||||
Represents a GUI component
|
||||
"""
|
||||
def __init__(self, id_: str):
|
||||
def __init__(self, id_: str, observers: List[ViewObserver] = None):
|
||||
self.id = id_
|
||||
self.observers = observers if observers else []
|
||||
|
||||
def add_observer(self, obs):
|
||||
self.observers.append(obs)
|
||||
|
||||
|
||||
class SpacerComponent(ViewComponent):
|
||||
@@ -157,6 +167,14 @@ class TextInputComponent(ViewComponent):
|
||||
else:
|
||||
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:
|
||||
if self.value is not None:
|
||||
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.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):
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ from bauh.api.abstract.handler import ProcessWatcher, TaskManager
|
||||
from bauh.api.abstract.model import SoftwarePackage, PackageHistory, PackageUpdate, PackageSuggestion, \
|
||||
SuggestionPriority, CustomSoftwareAction
|
||||
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.config import save_config
|
||||
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_ICON = re.compile(r'Icon\s*=\s*.+\n')
|
||||
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):
|
||||
@@ -74,9 +96,13 @@ class AppImageManager(SoftwareManager):
|
||||
if not os.path.isdir(default_path):
|
||||
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_version = TextInputComponent(label=self.i18n['version'].capitalize())
|
||||
file_chooser.observers.append(ManualInstallationFileObserver(input_name, input_version))
|
||||
|
||||
input_description = TextInputComponent(label=self.i18n['description'].capitalize())
|
||||
|
||||
cat_ops = [InputOption(label=self.i18n['category.none'].capitalize(), value=0)]
|
||||
|
||||
@@ -11,7 +11,7 @@ from PyQt5.QtWidgets import QRadioButton, QGroupBox, QCheckBox, QComboBox, QGrid
|
||||
|
||||
from bauh.api.abstract.view import SingleSelectComponent, InputOption, MultipleSelectComponent, SelectViewType, \
|
||||
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.colors import RED
|
||||
from bauh.view.util import resource
|
||||
@@ -428,6 +428,15 @@ class ComboSelectQt(QGroupBox):
|
||||
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):
|
||||
|
||||
def __init__(self, model: TextInputComponent):
|
||||
@@ -440,7 +449,7 @@ class TextInputQt(QGroupBox):
|
||||
if self.model.max_width > 0:
|
||||
self.setMaximumWidth(self.model.max_width)
|
||||
|
||||
self.text_input = QLineEdit()
|
||||
self.text_input = QLineEditObserver()
|
||||
|
||||
if model.only_int:
|
||||
self.text_input.setValidator(QIntValidator())
|
||||
@@ -457,10 +466,11 @@ class TextInputQt(QGroupBox):
|
||||
|
||||
self.text_input.textChanged.connect(self._update_model)
|
||||
|
||||
self.model.observers.append(self.text_input)
|
||||
self.layout().addWidget(self.text_input, 0, 1)
|
||||
|
||||
def _update_model(self, text: str):
|
||||
self.model.value = text
|
||||
self.model.set_value(val=text, caller=self)
|
||||
|
||||
|
||||
class MultipleSelectQt(QGroupBox):
|
||||
@@ -754,7 +764,7 @@ class FormQt(QGroupBox):
|
||||
return tip_icon
|
||||
|
||||
def _new_text_input(self, c: TextInputComponent) -> Tuple[QLabel, QLineEdit]:
|
||||
line_edit = QLineEdit()
|
||||
line_edit = QLineEditObserver()
|
||||
|
||||
if c.only_int:
|
||||
line_edit.setValidator(QIntValidator())
|
||||
@@ -773,9 +783,10 @@ class FormQt(QGroupBox):
|
||||
line_edit.setEnabled(False)
|
||||
|
||||
def update_model(text: str):
|
||||
c.value = text
|
||||
c.set_value(val=text, caller=line_edit)
|
||||
|
||||
line_edit.textChanged.connect(update_model)
|
||||
c.observers.append(line_edit)
|
||||
|
||||
label = QWidget()
|
||||
label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
|
||||
@@ -819,7 +830,7 @@ class FormQt(QGroupBox):
|
||||
return field_container
|
||||
|
||||
def _new_file_chooser(self, c: FileChooserComponent) -> Tuple[QLabel, QLineEdit]:
|
||||
chooser = QLineEdit()
|
||||
chooser = QLineEditObserver()
|
||||
chooser.setReadOnly(True)
|
||||
|
||||
if c.max_width > 0:
|
||||
@@ -828,6 +839,7 @@ class FormQt(QGroupBox):
|
||||
if c.file_path:
|
||||
chooser.setText(c.file_path)
|
||||
|
||||
c.observers.append(chooser)
|
||||
chooser.setPlaceholderText(self.i18n['view.components.file_chooser.placeholder'])
|
||||
|
||||
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)
|
||||
|
||||
if file_path:
|
||||
c.file_path = file_path
|
||||
chooser.setText(file_path)
|
||||
c.set_file_path(file_path)
|
||||
|
||||
chooser.setCursorPosition(0)
|
||||
|
||||
def clean_path():
|
||||
c.file_path = None
|
||||
chooser.setText('')
|
||||
c.set_file_path(None)
|
||||
|
||||
chooser.mousePressEvent = open_chooser
|
||||
|
||||
|
||||
Reference in New Issue
Block a user