presik_pos/app/commons/dialogs.py

382 lines
13 KiB
Python

# -*- coding: UTF-8 -*-
import os
from collections import OrderedDict
# from PyQt5.QtWidgets import (
# QDialog, QAbstractItemView, QVBoxLayout, QHBoxLayout, QLabel, QWidget,
# QTreeView, QLineEdit, QTableView, QCompleter, QDesktopWidget
# )
# from PyQt5.QtGui import QStandardItem, QStandardItemModel, QPixmap
# from PyQt5.QtCore import Qt, pyqtSlot, QModelIndex
from PySide6.QtWidgets import (
QDialog, QAbstractItemView, QVBoxLayout, QHBoxLayout, QLabel, QWidget,
QTreeView, QLineEdit, QTableView, QCompleter
)
from PySide6.QtGui import QStandardItem, QStandardItemModel, QPixmap, QGuiApplication
from PySide6.QtCore import Qt, Slot, QModelIndex
from .qt_models import get_simple_model
from .forms import GridForm
from .buttons import ActionButton
__all__ = ['QuickDialog', 'SearchDialog', 'HelpDialog', 'FactoryIcons']
current_dir = os.path.dirname(__file__)
_SIZE = (500, 200)
def get_screen():
screen = QGuiApplication.primaryScreen().size()
# screen = QDesktopWidget().screenGeometry()
width = screen.width()
height = screen.height()
return width, height
class QuickDialog(QDialog):
def __init__(self, parent, kind, string=None, data=None, widgets=None,
icon=None, size=None, readonly=False, buttons=True):
super(QuickDialog, self).__init__(parent)
# Size arg is in deprecation
if not size:
size = _SIZE
self.factory = None
self.readonly = readonly
self.parent = parent
self.parent_model = None
titles = {
'warning': 'Aviso...',
'form': 'Formulario...',
'info': 'Informacion...',
'action': 'Accion...',
'help': 'Ayuda...',
'error': 'Error...',
'question': 'Pregunta...',
'selection': 'Seleccion...',
None: 'Dialogo...',
}
self.setWindowTitle(titles[kind])
self.setModal(True)
self.setParent(parent)
self.factory = FactoryIcons()
self.default_widget_focus = None
self.kind = kind
self.widgets = widgets
self.data = data
string_widget = None
self.data_widget = None
_buttons = None
row_stretch = 1
self.main_vbox = QVBoxLayout()
self.sub_hbox = QHBoxLayout()
# Add main message
if string:
# For simple dialog
string_widget = QLabel(string)
string_widget.setObjectName('label_dialog')
string_widget.setAlignment(Qt.AlignCenter | Qt.AlignVCenter)
if widgets and (kind == 'help' or kind == 'info'):
self.data_widget = widgets[0]
elif kind in ('action', 'form'):
if widgets:
self.data_widget = widgets[0]
elif data:
self.data_widget = GridForm(parent, OrderedDict(data))
elif kind == 'selection':
self.name = data['name']
self.data_widget = self.set_selection(parent, data)
elif widgets:
self.data_widget = GridForm(parent, OrderedDict(widgets))
if string_widget:
self.main_vbox.addWidget(string_widget, 0)
if self.data_widget:
if isinstance(self.data_widget, QWidget):
row_stretch += 1
size = (size[0], size[1] + 200)
self.sub_hbox.addWidget(self.data_widget, 0)
else:
self.sub_hbox.addLayout(self.data_widget, 0)
self.ok_button = ActionButton('ok', self.dialog_accepted)
self.ok_button.setFocus()
self.ok_button.setDefault(True)
self.cancel_button = ActionButton('cancel', self.dialog_rejected)
_buttons = []
if kind in ('info', 'help', 'warning', 'question', 'error'):
if kind in ('warning', 'question', 'form'):
_buttons.append(self.cancel_button)
_buttons.append(self.ok_button)
elif kind in ('action', 'selection', 'form'):
_buttons.extend([self.cancel_button, self.ok_button])
self.buttonbox = QHBoxLayout()
if buttons:
for b in _buttons:
self.buttonbox.addWidget(b, 1)
self.buttonbox.setContentsMargins(0, 20, 0, 10)
self.main_vbox.addLayout(self.sub_hbox, 1)
self.main_vbox.setContentsMargins(20, 20, 20, 10)
self.main_vbox.addLayout(self.buttonbox, 1)
self.main_vbox.insertStretch(row_stretch, 0)
self.setLayout(self.main_vbox)
self.setSizeGripEnabled(True)
if kind in ('info', 'error'):
self.show()
def exec_(self, args=None):
res = None
res = super(QuickDialog, self).exec()
if hasattr(self, 'data_widget') and isinstance(self.data_widget, GridForm):
self.data_widget.set_focus()
if self.kind == 'action':
pass
return res
def show(self):
super(QuickDialog, self).show()
self.setFocus()
self.active = True
def hide(self):
super(QuickDialog, self).hide()
self.parent.setFocus()
self.active = False
def add_filter(self, layout):
self.main_vbox.addLayout(layout, 0)
def add_widget(self, widget):
_ = self.sub_hbox.takeAt(0)
self.sub_hbox.addLayout(widget, 0)
def set_info(self, info):
if hasattr(self, 'label_info'):
self.label_info.setText(info)
def set_widgets(self, widgets):
if widgets:
# Set default focus to first widget created
self.default_widget_focus = widgets[0]
def close(self):
self.active = False
super(QuickDialog, self).close()
def closeEvent(self, event):
super(QuickDialog, self).closeEvent(event)
def dialog_rejected(self):
print('cancell quitdialog')
try:
self.parent.label_input.setFocus()
except Exception:
pass
self.setResult(0)
self.hide()
def dialog_accepted(self):
if self.kind in ('action', 'selection', 'warning', 'question'):
self.setResult(1)
self.done(1)
self.hide()
def keyPressEvent(self, event):
key = event.key()
if key == Qt.Key_Escape:
self.dialog_rejected()
else:
super(QuickDialog, self).keyPressEvent(event)
def set_selection(self, obj, data):
self.set_simple_model()
setattr(obj, data['name'] + '_model', self.data_model)
self.parent_model = data.get('parent_model')
self.treeview = QTreeView()
self.treeview.setRootIsDecorated(False)
self.treeview.setColumnHidden(0, True)
self.treeview.setItemsExpandable(False)
self.treeview.setAlternatingRowColors(True)
self.treeview.setSelectionBehavior(QAbstractItemView.SelectRows)
self.treeview.setModel(self.data_model)
self.treeview.clicked.connect(self.field_selection_changed)
self.treeview.activated.connect(self.field_selection_changed)
self.update_values(self.data['values'])
# By default first row must be selected
item = self.data_model.item(0, 0)
idx = self.data_model.indexFromItem(item)
self.treeview.setCurrentIndex(idx)
return self.treeview
def update_values(self, values):
self.data_model.removeRows(0, self.data_model.rowCount())
self._insert_items(self.data_model, values)
self.treeview.resizeColumnToContents(0)
def set_simple_model(self):
self.data_model = QStandardItemModel(0, len(self.data['heads']), self)
_horizontal = Qt.Horizontal
for i, h in enumerate(self.data['heads'], 0):
self.data_model.setHeaderData(i, _horizontal, h)
def _insert_items(self, model, values):
ItemIsEnabled, ItemIsSelectable = Qt.ItemIsEnabled, Qt.ItemIsSelectable
insertRow = self.data_model.insertRow
for value in values:
row = []
row_append = row.append
for v in value:
itemx = QStandardItem(v)
itemx.setFlags(ItemIsEnabled | ItemIsSelectable)
row_append(itemx)
insertRow(0, row)
self.data_model.sort(0, Qt.AscendingOrder)
@Slot(QModelIndex)
def field_selection_changed(self, qm_index):
if not self.readonly:
item_id = self.data_model.item(qm_index.row(), 0).text()
item_name = self.data_model.item(qm_index.row(), 1).text()
if self.parent_model is not None:
self.parent_model[self.name] = item_id
if hasattr(self.parent, 'field_' + self.name):
field = getattr(self.parent, 'field_' + self.name)
if hasattr(field, 'setText'):
field.setText(item_name)
else:
setattr(self.parent, 'field_' + self.name + '_name', item_name)
setattr(self.parent, 'field_' + self.name + '_id', int(item_id))
action = getattr(self.parent, 'action_' + self.name + '_selection_changed')
action()
self.dialog_accepted()
class SearchDialog(QDialog):
def __init__(self, parent, headers, values, on_activated,
hide_headers=False, completion_column=None, title=None):
super(SearchDialog, self).__init__(parent)
self.parent = parent
self.headers = headers
self.values = values
if not title:
title = 'Search Products...'
self.setWindowTitle(title)
self._product_line = QLineEdit()
self.table_view = QTableView()
button_cancel = ActionButton('cancel', self.on_reject)
vbox = QVBoxLayout()
hbox = QHBoxLayout()
hbox.addWidget(button_cancel)
vbox.addWidget(self._product_line)
vbox.addLayout(hbox)
self.setLayout(vbox)
self.completer = QCompleter()
self.treeview_search_product = QTreeView()
if hide_headers:
col_headers = self.treeview_search_product.header()
col_headers.hide()
self.completer.setPopup(self.treeview_search_product)
self._product_line.setCompleter(self.completer)
self.set_model()
self.completer.activated.connect(self.on_accept)
self.completer.setFilterMode(Qt.MatchStartsWith)
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
self.completer.setCompletionColumn(2)
self.completer.activated.connect(on_activated)
def set_model(self):
headers_name = (h[1] for h in self.headers)
self.model = get_simple_model(self.parent, self.values, headers_name)
self.completer.setModel(self.model)
def get_selected_index(self):
model_index = self._get_model_index()
idx = self.model.index(model_index.row(), 0)
return idx.data()
def get_selected_data(self):
model_index = self._get_model_index()
data = {}
i = 0
for h, _ in self.headers:
data[h] = self.model.index(model_index.row(), i).data()
i += 1
return data
def _get_model_index(self):
item_view = self.completer.popup()
index = item_view.currentIndex()
proxy_model = self.completer.completionModel()
model_index = proxy_model.mapToSource(index)
return model_index
def on_accept(self):
self.accept()
def on_reject(self):
self.reject()
class HelpDialog(QuickDialog):
def __init__(self, parent):
self.treeview = QTreeView()
self.treeview.setRootIsDecorated(False)
self.treeview.setAlternatingRowColors(True)
self.treeview.setSelectionBehavior(QAbstractItemView.SelectRows)
self.treeview.setEditTriggers(QAbstractItemView.NoEditTriggers)
width, height = get_screen()
super(HelpDialog, self).__init__(parent, 'help', widgets=[self.treeview])
self.setFixedSize(int(width * 0.3), int(height * 0.7))
self.set_info('Keys Shortcuts...')
self.hide()
def set_shortcuts(self, shortcuts):
model = self._help_model(shortcuts)
self.treeview.setModel(model)
header = self.treeview.header()
header.resizeSection(0, 250)
def _help_model(self, shortcuts):
model = QStandardItemModel(0, 2, self)
model.setHeaderData(0, Qt.Horizontal, 'Accion')
model.setHeaderData(1, Qt.Horizontal, 'Atajo')
for short in shortcuts:
model.insertRow(0)
model.setData(model.index(0, 0), short[0])
model.setData(model.index(0, 1), short[1])
return model
class FactoryIcons(object):
def __init__(self):
name_icons = ['print', 'warning', 'info', 'error', 'question']
self.icons = {}
for name in name_icons:
path_icon = os.path.join(current_dir, '..', 'share', 'icon-' + name + '.png')
if not os.path.exists(path_icon):
continue
_qpixmap_icon = QPixmap()
_qpixmap_icon.load(path_icon)
_icon_label = QLabel()
_icon_label.setAlignment(Qt.AlignCenter | Qt.AlignCenter)
_icon_label.setPixmap(_qpixmap_icon.scaledToHeight(48))
self.icons[name] = _icon_label