Dev #7

Merged
foefl merged 74 commits from dev into main 2026-07-31 14:19:01 +00:00
5 changed files with 292 additions and 157 deletions
Showing only changes of commit 9cfe53509f - Show all commits
+26
View File
@@ -0,0 +1,26 @@
def _get_leafs(data):
if isinstance(data, dict):
for value in data.values():
yield from _get_leafs(value)
elif isinstance(data, (list, tuple, set)):
for item in data:
yield from _get_leafs(item)
else:
yield data
def _get_leaf_dicts(data):
if isinstance(data, dict):
has_inner_dicts = False
for value in data.values():
for inner_dict in _get_leaf_dicts(value):
has_inner_dicts = True
yield inner_dict
if not has_inner_dicts:
yield data
elif isinstance(data, (list, tuple, set)):
for item in data:
yield from _get_leaf_dicts(item)
+3 -3
View File
@@ -147,7 +147,7 @@ def initrec_company_get_initial_recording(
row = ret.fetchone() row = ret.fetchone()
assert row, "row was not obtained" assert row, "row was not obtained"
return row._asdict() return row._asdict() # type: ignore
def initrec_company_delete_initial_recording( def initrec_company_delete_initial_recording(
@@ -196,7 +196,7 @@ def initrec_person_update_initial_recording(
def initrec_person_get_initial_recording( def initrec_person_get_initial_recording(
id_: RecId, id_: RecId,
) -> dict[str, Any]: ) -> dict[str, Any]:
logger.debug("[Call backend] get_initial_recording") logger.debug("[Call backend] get_initial_recording person")
stmt = db.grunderfassung_personen.select().where( stmt = db.grunderfassung_personen.select().where(
db.grunderfassung_personen.c.pers_id == id_ db.grunderfassung_personen.c.pers_id == id_
) )
@@ -209,7 +209,7 @@ def initrec_person_get_initial_recording(
row = ret.fetchone() row = ret.fetchone()
assert row, "row was not obtained" assert row, "row was not obtained"
return row._asdict() return row._asdict() # type: ignore
def initrec_person_delete_initial_recording( def initrec_person_delete_initial_recording(
+37
View File
@@ -13,10 +13,47 @@ from pydantic import (
field_validator, field_validator,
model_validator, model_validator,
) )
from pydantic_core import ErrorDetails
ValidAge = Annotated[int, Field(ge=0, le=99)] ValidAge = Annotated[int, Field(ge=0, le=99)]
# // validation translation
GERMAN_ERROR_MESSAGES: Final[dict[str, str]] = {
"missing": "Dieses Feld ist ein Pflichtfeld.",
"int_parsing": "Bitte eine gültige Ganzzahl eingeben.",
"float_parsing": "Bitte eine gültige Dezimalzahl eingeben.",
"string_too_short": "Der Text ist zu kurz. Er muss mindestens {min_length} Zeichen lang sein.",
"string_too_long": "Der Text ist zu lang. Er darf maximal {max_length} Zeichen lang sein.",
"greater_than": "Der Wert muss größer als {gt} sein.",
}
def translate_pydantic_errors(
errors: list[ErrorDetails],
) -> list[ErrorDetails]:
translated_errors: list[ErrorDetails] = []
for error in errors:
err_type = error.get("type", None)
if err_type is None or err_type not in GERMAN_ERROR_MESSAGES:
error["msg"] = "[fehleden Übersetzung, nur Englisch]: " + error["msg"]
translated_errors.append(error)
continue
msg_template = GERMAN_ERROR_MESSAGES[err_type]
ctx = error.get("ctx", {})
try:
error["msg"] = msg_template.format(**ctx)
except KeyError:
error["msg"] = msg_template
translated_errors.append(error)
return translated_errors
def _parse_json(value: Any) -> str: def _parse_json(value: Any) -> str:
if isinstance(value, datetime.date): if isinstance(value, datetime.date):
return value.isoformat() return value.isoformat()
+2
View File
@@ -911,6 +911,7 @@ INITREC_COMP = [
required=False, required=False,
key="Metadaten_nutzer", key="Metadaten_nutzer",
readonly=True, readonly=True,
ignore_get_data=True,
), ),
FormField( FormField(
"Fallnummer", "Fallnummer",
@@ -956,6 +957,7 @@ INITREC_PERSON = [
required=False, required=False,
key="Metadaten_nutzer", key="Metadaten_nutzer",
readonly=True, readonly=True,
ignore_get_data=True,
), ),
FormField( FormField(
"Wiedereintrittsdatum", "Wiedereintrittsdatum",
+224 -154
View File
@@ -4,13 +4,11 @@ import copy
import dataclasses as dc import dataclasses as dc
import datetime import datetime
import enum import enum
import pickle
import re import re
import sys import sys
import traceback import traceback
from collections import defaultdict from collections import defaultdict
from collections.abc import Container, Iterable, Sequence from collections.abc import Container, Iterable, Sequence
from pathlib import Path
from pprint import pformat from pprint import pformat
from typing import ( from typing import (
TYPE_CHECKING, TYPE_CHECKING,
@@ -26,7 +24,6 @@ from typing import (
) )
from typing_extensions import override from typing_extensions import override
from dopt_basics import datetime as dopt_dt
from pydantic import ( from pydantic import (
ValidationError, ValidationError,
) )
@@ -36,7 +33,6 @@ from PySide6.QtCore import (
QEvent, QEvent,
QObject, QObject,
Qt, Qt,
QTime,
QTimer, QTimer,
QtMsgType, QtMsgType,
Signal, Signal,
@@ -84,6 +80,7 @@ from wce_crm.data_models import (
FlatBaseModel, FlatBaseModel,
Grunderfassung_Personen, Grunderfassung_Personen,
Grunderfassung_Unternehmen, Grunderfassung_Unternehmen,
translate_pydantic_errors,
) )
from wce_crm.form_defs import ( from wce_crm.form_defs import (
INITREC_COMP, INITREC_COMP,
@@ -166,36 +163,6 @@ def unmerge_dict_to_list(
return [dict(zip(keys, row)) for row in zip(*value_lists)] return [dict(zip(keys, row)) for row in zip(*value_lists)]
# TODO check removal or move to basics package
def _get_leafs(data):
if isinstance(data, dict):
for value in data.values():
yield from _get_leafs(value)
elif isinstance(data, (list, tuple, set)):
for item in data:
yield from _get_leafs(item)
else:
yield data
# TODO check removal or move to basics package
def _get_leaf_dicts(data):
if isinstance(data, dict):
has_inner_dicts = False
for value in data.values():
for inner_dict in _get_leaf_dicts(value):
has_inner_dicts = True
yield inner_dict
if not has_inner_dicts:
yield data
elif isinstance(data, (list, tuple, set)):
for item in data:
yield from _get_leaf_dicts(item)
def pprint_registry(widget_registry: WidgetRegistry) -> None: def pprint_registry(widget_registry: WidgetRegistry) -> None:
print("\n\n>>> Widget registry:") print("\n\n>>> Widget registry:")
for key, entry in widget_registry.items(): for key, entry in widget_registry.items():
@@ -665,8 +632,6 @@ def _build_ui_recursively(
else: else:
full_key = field.key full_key = field.key
widget: QWidget
match field.type: match field.type:
case FormFieldType.GROUP: case FormFieldType.GROUP:
group_box = QGroupBox(field.label) group_box = QGroupBox(field.label)
@@ -686,11 +651,6 @@ def _build_ui_recursively(
widget_registry=widget_registry, widget_registry=widget_registry,
prefix=prefix, prefix=prefix,
) )
# TODO remove
# widget_registry[full_key] = {
# "widget": widget,
# "form_field": field,
# }
keys.append(full_key) keys.append(full_key)
return keys return keys
@@ -722,7 +682,7 @@ def reset_form(
form_field = registry_entry["form_field"] form_field = registry_entry["form_field"]
# TODO check if this behaviour is correct in other contexts, deactivated because of # TODO check if this behaviour is correct in other contexts, deactivated because of
# TODO company search widget # company search widget
# if form_field.readonly: # if form_field.readonly:
# continue # continue
@@ -1410,6 +1370,7 @@ class AutoForm(QWidget):
) -> None: ) -> None:
super().__init__() super().__init__()
self.STATE = state self.STATE = state
self.SESSION_USER_KEY: Final[str] = "Metadaten_nutzer"
self.cfg = state.cfg self.cfg = state.cfg
self.setStyleSheet(""" self.setStyleSheet("""
QGroupBox { QGroupBox {
@@ -1515,40 +1476,21 @@ class AutoForm(QWidget):
self.debug_form_data: dict[str, Any] = {} self.debug_form_data: dict[str, Any] = {}
if self.add_buttons: if self.add_buttons:
self.layout_btn = QHBoxLayout() self.edit_buttons = EditButtons(add_reset_btn=True)
self.main_layout.addLayout(self.layout_btn) reset_btn = self.edit_buttons.reset_btn
# save assert reset_btn
self.save_btn_txt_enabled = "Speichern (Strg + S)" self.save_btn = self.edit_buttons.save_btn
self.save_btn_txt_disabled = "Wird gespeichert..." self.reset_btn = reset_btn
self.save_btn = QPushButton(self.save_btn_txt_enabled) self.delete_btn = self.edit_buttons.delete_btn
self.save_btn.setShortcut("Ctrl+S")
self.save_btn.setFixedHeight(50)
self.save_btn.setSizePolicy(
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed
)
self.save_btn.clicked.connect(self.save_data) self.save_btn.clicked.connect(self.save_data)
self.layout_btn.addWidget(self.save_btn)
# reset
self.reset_btn = QPushButton("Zurücksetzen (Strg + Z)")
self.reset_btn.setShortcut("Ctrl+Z")
self.reset_btn.setFixedHeight(50)
self.reset_btn.setSizePolicy(
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed
)
self.reset_btn.clicked.connect(self.reset_form) self.reset_btn.clicked.connect(self.reset_form)
self.layout_btn.addWidget(self.reset_btn)
# delete
self.delete_btn = QPushButton("Eintrag löschen (Strg + L)")
self.delete_btn.setShortcut("Ctrl+L")
self.delete_btn.setFixedHeight(50)
self.delete_btn.setSizePolicy(
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed
)
self.delete_btn.clicked.connect(self._delete_data) self.delete_btn.clicked.connect(self._delete_data)
self.layout_btn.addWidget(self.delete_btn)
self.main_layout.addWidget(self.edit_buttons)
logger_auto_form.debug( logger_auto_form.debug(
"Initialised Auto Form Widget. Registry:%s", "[Auto-Form] Initialised Auto Form Widget. Registry:%s",
pformat_registry(self.widget_registry), pformat_registry(self.widget_registry),
) )
@@ -1561,11 +1503,11 @@ class AutoForm(QWidget):
except ValueError: except ValueError:
index = None index = None
self.STATE.rec_id = index self.STATE.rec_id = index
logger_gui.debug("Set index to %d, new state: %s", index, self.STATE) logger_gui.debug("[Auto-Form] Set index to %s, new state: %s", index, self.STATE)
def _disable_save(self) -> None: def _disable_save(self) -> None:
self.save_btn.setEnabled(False) self.save_btn.setEnabled(False)
self.save_btn.setText(self.save_btn_txt_disabled) self.save_btn.setText(self.edit_buttons.save_btn_txt_disabled)
def _enable_save( def _enable_save(
self, self,
@@ -1573,7 +1515,7 @@ class AutoForm(QWidget):
) -> None: ) -> None:
QTimer.singleShot(timeout, lambda: self.save_btn.setEnabled(True)) QTimer.singleShot(timeout, lambda: self.save_btn.setEnabled(True))
QTimer.singleShot(timeout + 1, lambda: self.save_btn.setShortcut("Ctrl+S")) QTimer.singleShot(timeout + 1, lambda: self.save_btn.setShortcut("Ctrl+S"))
self.save_btn.setText(self.save_btn_txt_enabled) self.save_btn.setText(self.edit_buttons.save_btn_txt_enabled)
def _activate_delete(self) -> None: def _activate_delete(self) -> None:
if self.STATE.rec_id is not None: if self.STATE.rec_id is not None:
@@ -1589,35 +1531,32 @@ class AutoForm(QWidget):
def _load_data( def _load_data(
self, self,
lookup_id: int | None = None, lookup_id: int | None,
) -> None: ) -> None:
if DEBUG_NO_DATABASE: if DEBUG_NO_DATABASE:
return return
logger_auto_form.info(">>>> LOAD CLICKED") logger_auto_form.info("[Auto-Form] Load data method...")
if lookup_id is None:
# only debugging
lookup_id = self.STATE.rec_id
self.reset_form() self.reset_form()
logger_auto_form.debug("Lookup ID: %d", lookup_id) logger_auto_form.debug("[Auto-Form] Lookup ID: %s", lookup_id)
if lookup_id is not None and lookup_id > 0: if lookup_id is not None:
logger_auto_form.debug("Load from DB:") logger_auto_form.debug("Load from DB:")
loaded_data = self.cfg.data_get(lookup_id) loaded_data = self.cfg.data_get(lookup_id)
else: else:
logger_auto_form.error("Loading: Lookup ID 0 or NULL. Do nothing!") logger_auto_form.debug("[Auto-Form] Loading: Lookup ID NULL. Do nothing!")
return return
logger_auto_form.debug( logger_auto_form.debug(
"Loaded data dict:\n%s Passing to Pydantic...", pformat(loaded_data) "[Auto-Form] Loaded data dict:\n%s Passing to Pydantic...", pformat(loaded_data)
) )
model = self.cfg.model(**loaded_data) model = self.cfg.model(**loaded_data)
logger_auto_form.debug("Loaded to Pydantic.") logger_auto_form.debug("[Auto-Form] Loaded to Pydantic.")
logger_auto_form.debug("Convert to GUI structure...") logger_auto_form.debug("[Auto-Form] Convert to GUI structure...")
form_data = model.to_gui() form_data = model.to_gui()
logger_auto_form.debug("Set form data...") logger_auto_form.debug("[Auto-Form] Set form data...")
logger_auto_form.debug("Form data:\n%s", pformat(form_data)) logger_auto_form.debug("[Auto-Form] Form data:\n%s", pformat(form_data))
self._set_form_data(form_data) self._set_form_data(form_data)
self.STATE.rec_id = lookup_id self.STATE.rec_id = lookup_id
self._activate_delete() self._activate_delete()
@@ -1625,12 +1564,13 @@ class AutoForm(QWidget):
def reset_form(self) -> None: def reset_form(self) -> None:
reset_form(self.widget_registry) reset_form(self.widget_registry)
self.STATE.rec_id = None self.STATE.rec_id = None
self.STATE.form_data = None
self._activate_delete() self._activate_delete()
def _get_form_data(self) -> dict[str, Any]: def _get_form_data(self) -> dict[str, Any]:
form_data = get_form_data(self.widget_registry) form_data = get_form_data(self.widget_registry)
logger_auto_form.debug("\n\n>>>>>>> [AutoForm] Call get form data:") logger_auto_form.debug("[Auto-Form] Call get form data:")
logger_auto_form.debug("Form Data:\n%s", pformat(form_data)) logger_auto_form.debug("[Auto-Form] Form Data:\n%s", pformat(form_data))
if DEBUG_GET_SET: if DEBUG_GET_SET:
self.debug_form_data = form_data self.debug_form_data = form_data
@@ -1641,7 +1581,7 @@ class AutoForm(QWidget):
self, self,
data: dict[str, Any], data: dict[str, Any],
) -> None: ) -> None:
logger_auto_form.debug("\n\n>>>>>>> [AutoForm] Call set form data:") logger_auto_form.debug("[Auto-Form] Call set form data...")
if DEBUG_GET_SET: if DEBUG_GET_SET:
data = self.debug_form_data data = self.debug_form_data
@@ -1651,7 +1591,10 @@ class AutoForm(QWidget):
self._load_data(self.STATE.rec_id) self._load_data(self.STATE.rec_id)
def _sync_GUI_to_state(self) -> None: def _sync_GUI_to_state(self) -> None:
self.STATE.form_data = self._get_form_data() form_data = self._get_form_data()
# TODO change usage of user ID (needs changes in model and backend)
form_data[self.SESSION_USER_KEY] = self.STATE.session.user_name
self.STATE.form_data = form_data
def validate(self) -> list[str]: def validate(self) -> list[str]:
return validate_form_data(self.widget_registry) return validate_form_data(self.widget_registry)
@@ -1661,8 +1604,6 @@ class AutoForm(QWidget):
new_state: AutoForm_State, new_state: AutoForm_State,
) -> None: ) -> None:
set_page_state(self.STATE, new_state) set_page_state(self.STATE, new_state)
# self.STATE.rec_id = new_state.rec_id
# self.STATE.form_data = new_state.form_data
self._sync_state_to_GUI() self._sync_state_to_GUI()
def get_state(self) -> AutoForm_State: def get_state(self) -> AutoForm_State:
@@ -1675,50 +1616,29 @@ class AutoForm(QWidget):
errors = self.validate() errors = self.validate()
if errors: if errors:
# errors: abort saving and show pop up window logger_auto_form.error(
error_text = ( "[Auto-Form] Error during GUI validation phase:\n%s", pformat(errors)
"Bitte füllen Sie die folgenden Pflichtfelder aus:\n\n"
+ "\n".join(errors)
) )
QMessageBox.warning(self, "Fehlende Angaben", error_text) GUI_validation_error_handling(errors)
self._enable_save() self._enable_save()
return return
# no errors: data can be saved logger_auto_form.info("[Auto-Form] Success! All data is valid")
logger_auto_form.info("Erfolg! Alle Daten sind valide.") logger_auto_form.info("[Auto-Form] Get form data call...")
logger_auto_form.info("Get form data call...") state = self.get_state()
form_data = self._get_form_data() form_data = state.form_data
assert form_data, "form data not set"
logger_auto_form.debug( logger_auto_form.debug("[Auto-Form] Get form data\n%s", pformat(form_data))
"\n\n------------>>>>>>>>> Get form data\n%s", pformat(form_data)
)
try: try:
logger_auto_form.debug("------------>>>>>>>>> Call Pydantic") logger_auto_form.debug("[Auto-Form] Call Pydantic...")
validated_data = self.cfg.model(**form_data) validated_data = self.cfg.model(**form_data)
# # TODO add user?
except ValidationError as e: except ValidationError as e:
# catch errors and show them in GUI logger_auto_form.error(
error_texts = [] "[Auto-Form] Error during Pydantic validation phase:\n%s", pformat(e.errors())
)
# Pydantic detailed error list pydantic_validation_error_handling(e)
for error in e.errors():
logger_gui.error("Error during validation phase:\n%s", pformat(error))
error_field = str(error["loc"][0])
reason = error["msg"]
error_texts.append(f"- {error_field}: {reason}")
# TODO: Is this needed and feasible?
# formatting red
# if fehlerhaftes_feld in self.widgets:
# self.widgets[fehlerhaftes_feld].setStyleSheet(
# "border: 1px solid red; background: #fef2f2;"
# )
# tell user what went wrong
QMessageBox.warning(self, "Eingabefehler", "\n".join(error_texts))
else: else:
if DEBUG_NO_DATABASE: if DEBUG_NO_DATABASE:
return return
@@ -1726,20 +1646,20 @@ class AutoForm(QWidget):
# save data to database # save data to database
db_data = validated_data.to_db(exclude=self.cfg.ignored_keys) db_data = validated_data.to_db(exclude=self.cfg.ignored_keys)
logger_auto_form.debug( logger_auto_form.debug(
("Form data with 'exlude' (must be saved in the database):\n%s"), "[Auto-Form] Form data with 'exlude' (must be saved in the database):\n%s",
pformat(db_data), pformat(db_data),
) )
if self.STATE.rec_id is None: if self.STATE.rec_id is None:
logger_auto_form.debug("Insert triggered") logger_auto_form.debug("[Auto-Form] Insert triggered...")
init_rec_id = self.cfg.data_insert(db_data) init_rec_id = self.cfg.data_insert(db_data)
assert isinstance(init_rec_id, int) assert isinstance(init_rec_id, int)
self.STATE.rec_id = init_rec_id self.STATE.rec_id = init_rec_id
else: else:
logger_auto_form.debug("Update triggered") logger_auto_form.debug("[Auto-Form] Update triggered...")
self.cfg.data_update(self.STATE.rec_id, db_data) self.cfg.data_update(self.STATE.rec_id, db_data)
logger_auto_form.info("Data saved successfully") logger_auto_form.info("[Auto-Form] Data saved successfully")
self.update_triggered.emit() self.update_triggered.emit()
self._activate_delete() self._activate_delete()
finally: finally:
@@ -3688,19 +3608,6 @@ class Page_Consulting(QWidget):
# state management # state management
self.STATE = Page_Consulting_State(session=session) self.STATE = Page_Consulting_State(session=session)
# self.current_id: InitRecId = -1
# self.COMPANY_FETAURES_MASTER_DATA: dict[str, str] = {
# "ma_unternehmensname": "Name:",
# "ma_branche": "Branche:",
# "ma_strasse": "Straße:",
# "ma_hausnummer": "Hausnummer:",
# "ma_plz": "PLZ:",
# "ma_ort": "Ort:",
# "ma_website": "Webseite:",
# "ma_mail": "E-Mail:",
# "ma_telefonnummer": "Telefon:",
# }
# Hauptlayout der Seite # Hauptlayout der Seite
outer_layout = QHBoxLayout(self) outer_layout = QHBoxLayout(self)
vert_layout = QVBoxLayout() vert_layout = QVBoxLayout()
@@ -3907,8 +3814,6 @@ class Page_Consulting(QWidget):
self, self,
new_state: Page_Consulting_State, new_state: Page_Consulting_State,
) -> None: ) -> None:
# TODO add correct loading behaviour
# TODO add validation (correct type with necessary information)
logger_page_consulting.debug("[Consulting] Loading with request:\n%s", new_state) logger_page_consulting.debug("[Consulting] Loading with request:\n%s", new_state)
set_page_state(self.STATE, new_state) set_page_state(self.STATE, new_state)
# child modules # child modules
@@ -4696,19 +4601,184 @@ def global_exception_handler(exc_type, exc_value, exc_traceback):
# message to user # message to user
# check if QApplication exists otherwise crashing of crash handler possible) # check if QApplication exists otherwise crashing of crash handler possible)
if QApplication.instance(): if QApplication.instance():
msg_box = QMessageBox() msg_box = get_error_message_box(
msg_box.setIcon(QMessageBox.Icon.Critical) QMessageBox.Icon.Critical,
msg_box.setWindowTitle("Kritischer Fehler") "Kritischer Fehler",
msg_box.setText( "Ein unerwarteter Fehler ist aufgetreten. Die Details wurden protokolliert.",
"Ein unerwarteter Fehler ist aufgetreten. Die Details wurden protokolliert." error_msg,
) )
# details for user or screenshots # msg_box.setIcon(QMessageBox.Icon.Critical)
msg_box.setDetailedText(error_msg) # msg_box.setWindowTitle("Kritischer Fehler")
# msg_box.setText(
# "Ein unerwarteter Fehler ist aufgetreten. Die Details wurden protokolliert."
# )
# # details for user or screenshots
# msg_box.setDetailedText(error_msg)
msg_box.exec() msg_box.exec()
sys.exit(1) sys.exit(1)
def get_error_message_box(
msg_type: QMessageBox.Icon,
title: str,
message: str,
detailed_text: str | None = None,
) -> QMessageBox:
msg_box = QMessageBox()
msg_box.setIcon(msg_type)
msg_box.setWindowTitle(title)
msg_box.setText(message)
if detailed_text is not None:
msg_box.setDetailedText(detailed_text)
return msg_box
def pydantic_validation_error_handling(
val_error: ValidationError,
) -> None:
error_texts: list[str] = []
translated_errors = translate_pydantic_errors(val_error.errors())
for error in translated_errors:
error_field = str(error["loc"][0])
reason = error["msg"]
path = "".join(error["loc"][:-1]) # type: ignore
error_texts.append(f"- {error_field}: {reason}, (Pfad: {path})")
msg_box = get_error_message_box(
QMessageBox.Icon.Warning,
"Fehler bei der Validierung der Eingabedaten",
(
"Bei der Validierung der Eingaben ist ein Fehler aufgetreten. Details "
"sind unten angefügt."
),
"\n".join(error_texts),
)
msg_box.exec()
def GUI_validation_error_handling(
errors: list[str],
) -> None:
error_text = "Bitte füllen Sie die folgenden Pflichtfelder aus:\n\n" + "\n".join(
errors
)
msg_box = get_error_message_box(
QMessageBox.Icon.Warning,
"Fehlende oder fehlerhafte Angaben",
error_text,
)
msg_box.exec()
# @dc.dataclass(slots=True)
# class EditButton:
# btn: QWidget
# txt_enabled: str
# txt_disabled: str
# @dc.dataclass(slots=True, kw_only=True)
# class EditButtonLayout:
# layout: QLayout
# save: EditButton
# delete: EditButton
# reset: EditButton | None
class EditButtons(QWidget):
def __init__(
self,
add_reset_btn: bool,
) -> None:
super().__init__()
layout_btn = QHBoxLayout(self)
layout_btn.setContentsMargins(0, 0, 0, 0)
# main_layout.addLayout(layout_btn) # TODO add in component
# save
self.save_btn_txt_enabled = "Speichern (Strg + S)"
self.save_btn_txt_disabled = "Wird gespeichert..."
self.save_btn = QPushButton(self.save_btn_txt_enabled)
self.save_btn.setShortcut("Ctrl+S")
self.save_btn.setFixedHeight(50)
self.save_btn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
# save_btn.clicked.connect(save_data) # TODO add in component
layout_btn.addWidget(self.save_btn)
# reset
self.reset_button: QPushButton | None = None
if add_reset_btn:
self.reset_btn = QPushButton("Zurücksetzen (Strg + Z)")
self.reset_btn.setShortcut("Ctrl+Z")
self.reset_btn.setFixedHeight(50)
self.reset_btn.setSizePolicy(
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed
)
# reset_btn.clicked.connect(reset_form) # TODO add in component
layout_btn.addWidget(self.reset_btn)
# delete
self.delete_btn = QPushButton("Eintrag löschen (Strg + L)")
self.delete_btn.setShortcut("Ctrl+L")
self.delete_btn.setFixedHeight(50)
self.delete_btn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
# delete_btn.clicked.connect(self._delete_data) # TODO add in component
layout_btn.addWidget(self.delete_btn)
# def get_edit_buttons(
# add_reset_btn: bool,
# ) -> EditButtonLayout:
# layout_btn = QHBoxLayout()
# # main_layout.addLayout(layout_btn) # TODO add in component
# # save
# save_btn_txt_enabled = "Speichern (Strg + S)"
# save_btn_txt_disabled = "Wird gespeichert..."
# save_btn = QPushButton(save_btn_txt_enabled)
# save_btn.setShortcut("Ctrl+S")
# save_btn.setFixedHeight(50)
# save_btn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
# # save_btn.clicked.connect(save_data) # TODO add in component
# edit_button_save = EditButton(save_btn, "Speichern (Strg + S)", "Wird gespeichert...")
# layout_btn.addWidget(save_btn)
# # reset
# edit_button_reset: EditButton | None = None
# if add_reset_btn:
# reset_btn = QPushButton("Zurücksetzen (Strg + Z)")
# reset_btn.setShortcut("Ctrl+Z")
# reset_btn.setFixedHeight(50)
# reset_btn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
# # reset_btn.clicked.connect(reset_form) # TODO add in component
# edit_button_reset = EditButton(
# save_btn, "Zurücksetzen (Strg + Z)", "Zurücksetzen (Strg + Z)"
# )
# layout_btn.addWidget(reset_btn)
# # delete
# delete_btn = QPushButton("Eintrag löschen (Strg + L)")
# delete_btn.setShortcut("Ctrl+L")
# delete_btn.setFixedHeight(50)
# delete_btn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
# edit_button_delete = EditButton(
# save_btn, "Eintrag löschen (Strg + L)", "Eintrag löschen (Strg + L)"
# )
# # delete_btn.clicked.connect(self._delete_data) # TODO add in component
# layout_btn.addWidget(delete_btn)
# return EditButtonLayout(
# layout=layout_btn,
# save=edit_button_save,
# delete=edit_button_delete,
# reset=edit_button_reset,
# )
def qt_message_handler(mode, context, message): def qt_message_handler(mode, context, message):
"""forwards internal Qt C++ warnings to Python loggers""" """forwards internal Qt C++ warnings to Python loggers"""
if mode == QtMsgType.QtInfoMsg: if mode == QtMsgType.QtInfoMsg: