mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-07 02:24:16 +02:00
substatus | confirmation dialog component
This commit is contained in:
@@ -83,4 +83,5 @@ manage_window.bt_about.tooltip=About
|
||||
warning.no_managers=There are no installed extensions. It will not be possible to intall and manage applications.
|
||||
confirmation=confirmation
|
||||
and=and
|
||||
error=error
|
||||
error=error
|
||||
action.cancelled=operation cancelled by the user
|
||||
@@ -85,4 +85,5 @@ manage_window.bt_about.tooltip=Sobre
|
||||
warning.no_managers=No hay extensiones instaladas. No será posible instalar y administrar aplicaciones.
|
||||
confirmation=confirmación
|
||||
and=y
|
||||
error=error
|
||||
error=error
|
||||
action.cancelled=operación cancelada por el usuario
|
||||
@@ -85,4 +85,5 @@ manage_window.bt_about.tooltip=Sobre
|
||||
warning.no_managers=Não há nenhuma extensão instalada. Não será possível instalar e gerenciar aplicações.
|
||||
confirmation=confirmação
|
||||
and=e
|
||||
error=erro
|
||||
error=erro
|
||||
action.cancelled=operação cancelada pelo usuário
|
||||
137
bauh/view/qt/components.py
Normal file
137
bauh/view/qt/components.py
Normal file
@@ -0,0 +1,137 @@
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import QRadioButton, QFormLayout, QGroupBox, QCheckBox, QComboBox, QGridLayout, QWidget, \
|
||||
QVBoxLayout, QLabel
|
||||
from bauh_api.abstract.view import SingleSelectComponent, SelectOption, MultipleSelectComponent, SelectViewType
|
||||
|
||||
|
||||
class RadioButtonQt(QRadioButton):
|
||||
|
||||
def __init__(self, model: SelectOption, model_parent: SingleSelectComponent):
|
||||
super(RadioButtonQt, self).__init__()
|
||||
self.model = model
|
||||
self.model_parent = model_parent
|
||||
self.toggled.connect(self._set_checked)
|
||||
|
||||
def _set_checked(self, checked: bool):
|
||||
if checked:
|
||||
self.model_parent.value = self.model
|
||||
|
||||
|
||||
class CheckboxQt(QCheckBox):
|
||||
|
||||
def __init__(self, model: SelectOption, model_parent: MultipleSelectComponent):
|
||||
super(CheckboxQt, self).__init__()
|
||||
self.model = model
|
||||
self.model_parent = model_parent
|
||||
self.stateChanged.connect(self._set_checked)
|
||||
|
||||
def _set_checked(self, state):
|
||||
if state == 2:
|
||||
self.model_parent.values.add(self.model)
|
||||
else:
|
||||
if self.model in self.model_parent.values:
|
||||
self.model_parent.values.remove(self.model)
|
||||
|
||||
|
||||
class ComboBoxQt(QComboBox):
|
||||
|
||||
def __init__(self, model: SingleSelectComponent):
|
||||
super(ComboBoxQt, self).__init__()
|
||||
self.model = model
|
||||
for idx, op in enumerate(self.model.options):
|
||||
self.addItem(op.label, op.value)
|
||||
|
||||
if model.value and model.value == op: # default
|
||||
self.setCurrentIndex(idx)
|
||||
|
||||
self.currentIndexChanged.connect(self._set_selected)
|
||||
|
||||
def _set_selected(self, idx: int):
|
||||
self.model.value = self.model.options[idx]
|
||||
|
||||
|
||||
class RadioSelectQt(QGroupBox):
|
||||
|
||||
def __init__(self, model: SingleSelectComponent):
|
||||
super(RadioSelectQt, self).__init__(model.label + ' :')
|
||||
self.model = model
|
||||
self.setStyleSheet("QGroupBox { font-weight: bold }")
|
||||
|
||||
grid = QGridLayout()
|
||||
self.setLayout(grid)
|
||||
|
||||
line, col = 0, 0
|
||||
for op in model.options:
|
||||
comp = RadioButtonQt(op, model)
|
||||
comp.setText(op.label)
|
||||
comp.setToolTip(op.tooltip)
|
||||
|
||||
if model.value and model.value == op:
|
||||
self.value = comp
|
||||
comp.setChecked(True)
|
||||
|
||||
grid.addWidget(comp, line, col)
|
||||
|
||||
if col + 1 == self.model.max_per_line:
|
||||
line += 1
|
||||
col = 0
|
||||
else:
|
||||
col += 1
|
||||
|
||||
|
||||
class ComboSelectQt(QGroupBox):
|
||||
|
||||
def __init__(self, model: SingleSelectComponent):
|
||||
super(ComboSelectQt, self).__init__()
|
||||
self.model = model
|
||||
self.setLayout(QGridLayout())
|
||||
self.setStyleSheet('QGridLayout {margin-left: 0} QLabel { font-weight: bold}')
|
||||
self.layout().addWidget(QLabel(model.label + ' :'), 0, 0)
|
||||
self.layout().addWidget(ComboBoxQt(model), 0, 1)
|
||||
|
||||
# class ComboSelectQt(QGroupBox):
|
||||
#
|
||||
# def __init__(self, model: SingleSelectComponent):
|
||||
# super(ComboSelectQt, self).__init__(model.label + ' :')
|
||||
# self.model = model
|
||||
# self.setLayout(QGridLayout())
|
||||
# self.setStyleSheet('QGridLayout {margin-left: 0} QLabel { font-weight: bold}')
|
||||
# self.layout().addWidget(ComboBoxQt(model), 0, 1)
|
||||
|
||||
|
||||
class MultipleSelectQt(QGroupBox):
|
||||
|
||||
def __init__(self, model: MultipleSelectComponent):
|
||||
super(MultipleSelectQt, self).__init__(model.label + ' :')
|
||||
self.setStyleSheet("QGroupBox { font-weight: bold }")
|
||||
self.model = model
|
||||
self._layout = QGridLayout()
|
||||
self.setLayout(self._layout)
|
||||
|
||||
line, col = 0, 0
|
||||
for op in model.options:
|
||||
comp = CheckboxQt(op, model)
|
||||
comp.setText(op.label)
|
||||
comp.setToolTip(op.tooltip)
|
||||
|
||||
if model.values and op in model.values:
|
||||
self.value = comp
|
||||
comp.setChecked(True)
|
||||
|
||||
self._layout.addWidget(comp, line, col)
|
||||
|
||||
if col + 1 == self.model.max_per_line:
|
||||
line += 1
|
||||
col = 0
|
||||
else:
|
||||
col += 1
|
||||
|
||||
|
||||
def new_single_select(model: SingleSelectComponent):
|
||||
if model.type == SelectViewType.RADIO:
|
||||
return RadioSelectQt(model)
|
||||
elif model.type == SelectViewType.COMBO:
|
||||
return ComboSelectQt(model)
|
||||
else:
|
||||
raise Exception("Unsupported type {}".format(model.type))
|
||||
|
||||
44
bauh/view/qt/confirmation.py
Normal file
44
bauh/view/qt/confirmation.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from typing import List
|
||||
|
||||
from PyQt5.QtWidgets import QMessageBox, QVBoxLayout, QLabel, QWidget
|
||||
from bauh_api.abstract.view import ViewComponent, SingleSelectComponent, MultipleSelectComponent
|
||||
|
||||
from bauh.view.qt.components import MultipleSelectQt, new_single_select
|
||||
|
||||
|
||||
class ConfirmationDialog(QMessageBox):
|
||||
|
||||
def __init__(self, title: str, body: str, locale_keys: dict, components: List[ViewComponent] = None):
|
||||
super(ConfirmationDialog, self).__init__()
|
||||
self.setWindowTitle(title)
|
||||
self.setStyleSheet('QLabel { margin-right: 25px; }')
|
||||
self.bt_yes = self.addButton(locale_keys['popup.button.yes'], QMessageBox.YesRole)
|
||||
self.addButton(locale_keys['popup.button.no'], QMessageBox.NoRole)
|
||||
|
||||
if body:
|
||||
if components:
|
||||
self.layout().addWidget(QLabel(body), 0, 1)
|
||||
else:
|
||||
self.setIcon(QMessageBox.Question)
|
||||
self.setText(body)
|
||||
|
||||
if components:
|
||||
comps_container = QWidget(parent=self)
|
||||
comps_container.setLayout(QVBoxLayout())
|
||||
|
||||
for idx, comp in enumerate(components):
|
||||
if isinstance(comp, SingleSelectComponent):
|
||||
inst = new_single_select(comp)
|
||||
elif isinstance(comp, MultipleSelectComponent):
|
||||
inst = MultipleSelectQt(comp)
|
||||
else:
|
||||
raise Exception("Cannot render instances of " + comp.__class__.__name__)
|
||||
|
||||
comps_container.layout().addWidget(inst)
|
||||
|
||||
self.layout().addWidget(comps_container, 1, 1)
|
||||
|
||||
self.exec_()
|
||||
|
||||
def is_confirmed(self):
|
||||
return self.clickedButton() == self.bt_yes
|
||||
@@ -7,6 +7,7 @@ from PyQt5.QtCore import QThread, pyqtSignal
|
||||
from bauh_api.abstract.controller import ApplicationManager
|
||||
from bauh_api.abstract.handler import ProcessWatcher
|
||||
from bauh_api.abstract.model import ApplicationStatus
|
||||
from bauh_api.abstract.view import InputViewComponent
|
||||
from bauh_api.exception import NoInternetException
|
||||
from bauh_api.util.cache import Cache
|
||||
|
||||
@@ -20,20 +21,21 @@ class AsyncAction(QThread, ProcessWatcher):
|
||||
signal_finished = pyqtSignal(object) # informs the main window that the action has finished
|
||||
signal_error = pyqtSignal(dict) # asks the GUI to show an error popup
|
||||
signal_status = pyqtSignal(str) # changes the GUI status message
|
||||
signal_substatus = pyqtSignal(str) # changes the GUI substatus message
|
||||
|
||||
def __init__(self):
|
||||
super(AsyncAction, self).__init__()
|
||||
self.wait_confirmation = False
|
||||
self.confirmation_res = None
|
||||
|
||||
def request_confirmation(self, title: str, body: str, options: dict) -> dict:
|
||||
def request_confirmation(self, title: str, body: str, options: List[InputViewComponent] = None) -> bool:
|
||||
self.wait_confirmation = True
|
||||
self.signal_confirmation.emit({'title': title, 'body': body, 'options': options})
|
||||
self.wait_user()
|
||||
return self.confirmation_res
|
||||
|
||||
def confirm(self, msg: dict):
|
||||
self.confirmation_res = msg
|
||||
def confirm(self, res: bool):
|
||||
self.confirmation_res = res
|
||||
self.wait_confirmation = False
|
||||
|
||||
def wait_user(self):
|
||||
@@ -53,6 +55,9 @@ class AsyncAction(QThread, ProcessWatcher):
|
||||
def change_status(self, status: str):
|
||||
self.signal_status.emit(status)
|
||||
|
||||
def change_substatus(self, substatus: str):
|
||||
self.signal_substatus.emit(substatus)
|
||||
|
||||
|
||||
class UpdateSelectedApps(AsyncAction):
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ from bauh.util import util
|
||||
from bauh.view.qt import dialog
|
||||
from bauh.view.qt.about import AboutDialog
|
||||
from bauh.view.qt.apps_table import AppsTable
|
||||
from bauh.view.qt.confirmation import ConfirmationDialog
|
||||
from bauh.view.qt.history import HistoryDialog
|
||||
from bauh.view.qt.info import InfoDialog
|
||||
from bauh.view.qt.root import is_root, ask_root_password
|
||||
@@ -29,7 +30,7 @@ DARK_ORANGE = '#FF4500'
|
||||
class ManageWindow(QWidget):
|
||||
__BASE_HEIGHT__ = 400
|
||||
|
||||
signal_user_res = pyqtSignal(dict)
|
||||
signal_user_res = pyqtSignal(bool)
|
||||
|
||||
def __init__(self, locale_keys: dict, icon_cache: Cache, manager: ApplicationManager, disk_cache: bool, download_icons: bool, screen_size, suggestions: bool, tray_icon=None):
|
||||
super(ManageWindow, self).__init__()
|
||||
@@ -133,6 +134,7 @@ class ManageWindow(QWidget):
|
||||
self.ref_checkbox_console = toolbar_console.addWidget(self.checkbox_console)
|
||||
|
||||
toolbar_console.addWidget(self._new_spacer())
|
||||
|
||||
self.layout.addWidget(toolbar_console)
|
||||
|
||||
self.textarea_output = QPlainTextEdit(self)
|
||||
@@ -184,6 +186,14 @@ class ManageWindow(QWidget):
|
||||
|
||||
self.layout.addWidget(self.toolbar_bottom)
|
||||
|
||||
self.toolbar_substatus = QToolBar()
|
||||
self.toolbar_substatus.addWidget(self._new_spacer())
|
||||
self.label_substatus = QLabel()
|
||||
self.toolbar_substatus.addWidget(self.label_substatus)
|
||||
self.toolbar_substatus.addWidget(self._new_spacer())
|
||||
self.layout.addWidget(self.toolbar_substatus)
|
||||
self._change_label_substatus('')
|
||||
|
||||
self.centralize()
|
||||
|
||||
self.filter_only_apps = True
|
||||
@@ -205,13 +215,14 @@ class ManageWindow(QWidget):
|
||||
action.signal_output.connect(self._update_action_output)
|
||||
action.signal_error.connect(self._show_error)
|
||||
action.signal_status.connect(self._change_label_status)
|
||||
action.signal_substatus.connect(self._change_label_substatus)
|
||||
self.signal_user_res.connect(action.confirm)
|
||||
|
||||
return action
|
||||
|
||||
def _ask_confirmation(self, msg: dict):
|
||||
res = dialog.ask_confirmation(msg['title'], msg['body'], self.locale_keys)
|
||||
self.signal_user_res.emit({'proceed': res, 'options': {}})
|
||||
diag = ConfirmationDialog(msg['title'], msg['body'], self.locale_keys)
|
||||
self.signal_user_res.emit(diag.is_confirmed())
|
||||
|
||||
def _show_error(self, msg: dict):
|
||||
dialog.show_error(title=msg['title'], body=msg['body'])
|
||||
@@ -385,6 +396,16 @@ class ManageWindow(QWidget):
|
||||
def _change_label_status(self, status: str):
|
||||
self.label_status.setText(status)
|
||||
|
||||
def _change_label_substatus(self, substatus: str):
|
||||
if not substatus:
|
||||
self.label_substatus.setText(substatus)
|
||||
self.toolbar_substatus.hide()
|
||||
else:
|
||||
if not self.toolbar_substatus.isVisible():
|
||||
self.toolbar_substatus.show()
|
||||
|
||||
self.label_substatus.setText("( {} )".format(substatus))
|
||||
|
||||
def apply_filters(self):
|
||||
if self.apps:
|
||||
visible_apps = len(self.apps)
|
||||
@@ -600,6 +621,7 @@ class ManageWindow(QWidget):
|
||||
self.extra_filters.setEnabled(False)
|
||||
|
||||
def finish_action(self):
|
||||
self._change_label_substatus('')
|
||||
self.ref_bt_about.setVisible(True)
|
||||
self.ref_progress_bar.setVisible(False)
|
||||
self.ref_label_updates.setVisible(True)
|
||||
@@ -610,6 +632,7 @@ class ManageWindow(QWidget):
|
||||
self.table_apps.setEnabled(True)
|
||||
self.input_search.setEnabled(True)
|
||||
self.label_status.setText('')
|
||||
self.label_substatus.setText('')
|
||||
self.ref_toolbar_search.setVisible(True)
|
||||
self.ref_toolbar_search.setEnabled(True)
|
||||
self.extra_filters.setEnabled(True)
|
||||
|
||||
Reference in New Issue
Block a user