generated from dopt-python/py311
better automatic export, prepare data validation for backend export
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import dataclasses as dc
|
||||
import datetime
|
||||
import enum
|
||||
import re
|
||||
import sys
|
||||
@@ -8,9 +10,10 @@ import time
|
||||
import uuid
|
||||
from collections.abc import Sequence
|
||||
from pprint import pprint
|
||||
from typing import Any, Protocol, TypeAlias, TypedDict
|
||||
from typing import Annotated, Any, Protocol, TypeAlias, TypedDict
|
||||
|
||||
import babel
|
||||
from pydantic import BaseModel, ConfigDict, EmailStr, Field, ValidationError, field_validator
|
||||
from PySide6.QtCore import QDate, QModelIndex, QStringListModel, Qt, QTimer, Signal
|
||||
from PySide6.QtGui import QAction, QStandardItem, QStandardItemModel
|
||||
from PySide6.QtWidgets import (
|
||||
@@ -83,7 +86,137 @@ def get_country_list_german() -> CountryList:
|
||||
)
|
||||
|
||||
|
||||
def get_list_germany_states() -> CountryList:
|
||||
states: list[tuple[str, str]] = []
|
||||
short_code_to_name: dict[str, str] = {}
|
||||
|
||||
STATE_LIST: list[tuple[str, str]] = [
|
||||
("Bayern", "BY"),
|
||||
("Niedersachen", "NI"),
|
||||
("Baden-Württemberg", "BW"),
|
||||
("Berlin", "BE"),
|
||||
("Brandenburg", "BB"),
|
||||
("Bremen", "HB"),
|
||||
("Hamburg", "HH"),
|
||||
("Hessen", "HE"),
|
||||
("Mecklenburg", "MV"),
|
||||
("Nordrhein-Westfalen", "NW"),
|
||||
("Rheinland-Pfalz", "RP"),
|
||||
("Saarland", "SL"),
|
||||
("Sachsen", "SN"),
|
||||
("Sachsen-Anhalt", "ST"),
|
||||
("Schleswig-Holstein", "SH"),
|
||||
("Thüringen", "TH"),
|
||||
]
|
||||
STATE_LIST.sort(key=lambda x: x[1])
|
||||
|
||||
for iso_code, country_name in STATE_LIST:
|
||||
states.append((country_name, iso_code))
|
||||
short_code_to_name[iso_code] = country_name
|
||||
|
||||
return CountryList(
|
||||
iso_to_country=short_code_to_name,
|
||||
for_dropdown=tuple(states),
|
||||
)
|
||||
|
||||
|
||||
COUNTRY_LIST = get_country_list_german()
|
||||
GERMAN_STATE_LIST = get_country_list_german()
|
||||
|
||||
|
||||
def pprint_registry(widget_registry: WidgetRegistry) -> None:
|
||||
print("---\n\n>>> Widget registry:")
|
||||
for key, entry in widget_registry.items():
|
||||
print(f"Key: {key}")
|
||||
print(f"\twidget: {entry['widget']}")
|
||||
print(f"\tfield key: {entry['form_field'].key}")
|
||||
print(f"\tfield type: {entry['form_field'].type}")
|
||||
|
||||
|
||||
class Grunderfassung_Unternehmen(BaseModel):
|
||||
Projektrelevanz: Grunderfassung_Projektrelevanz
|
||||
Kontaktperson: Grunderfassung_Kontaktperson
|
||||
Stammdaten: Grunderfassung_Stammdaten
|
||||
|
||||
|
||||
class Grunderfassung_Projektrelevanz(BaseModel):
|
||||
model_config = ConfigDict(str_strip_whitespace=True)
|
||||
|
||||
Projektrelevanz_relevanz: bool
|
||||
|
||||
@field_validator("Projektrelevanz_relevanz", mode="before")
|
||||
@classmethod
|
||||
def str_to_bool(cls, value: Any) -> Any:
|
||||
if isinstance(value, str):
|
||||
value = value.strip().lower()
|
||||
|
||||
if value == "ja":
|
||||
return True
|
||||
elif value == "nein":
|
||||
return False
|
||||
|
||||
raise ValueError("Wert muss 'ja', 'nein', True oder False sein.")
|
||||
|
||||
return value
|
||||
|
||||
|
||||
class Grunderfassung_Kontaktperson(BaseModel):
|
||||
model_config = ConfigDict(str_strip_whitespace=True)
|
||||
|
||||
KP_name_partner: str | None
|
||||
KP_titel: str | None
|
||||
KP_anrede_anschrift: str | None
|
||||
KP_name: str | None
|
||||
KP_vorname: str | None
|
||||
KP_festnetznummer: str | None
|
||||
KP_mobilfunknummer: str | None
|
||||
KP_email: EmailStr | None
|
||||
KP_funktion_beziehung: str | None
|
||||
KP_adresse: str | None
|
||||
|
||||
|
||||
ValidAge = Annotated[int, Field(ge=0, le=99)]
|
||||
|
||||
|
||||
class Grunderfassung_Stammdaten(BaseModel):
|
||||
model_config = ConfigDict(str_strip_whitespace=True)
|
||||
|
||||
Stammdaten_titel: str | None
|
||||
Stammdaten_anrede_anschrift: str
|
||||
Stammdaten_name: str
|
||||
Stammdaten_vorname: str | None
|
||||
Stammdaten_geburtsdatum: datetime.date | None
|
||||
Stammdaten_herkunftsland: str
|
||||
Stammdaten_staatsangehoerigkeit: str | None
|
||||
Stammdaten_rueckkehrer: bool | None
|
||||
Stammdaten_aufenthaltsort: str | None
|
||||
Stammdaten_strasse: str | None
|
||||
Stammdaten_hausnummer: str | None
|
||||
Stammdaten_PLZ: str | None
|
||||
Stammdaten_ort: str | None
|
||||
Stammdaten_bundesland: str | None
|
||||
Stammdaten_land: str | None
|
||||
Stammdaten_festnetznummer: str | None
|
||||
Stammdaten_mobilfunknummer: str | None
|
||||
Stammdaten_email: EmailStr | None
|
||||
Stammdaten_familienstand: str | None
|
||||
Stammdaten_anzahl_kinder: int | None
|
||||
Stammdaten_alter_kinder: list[ValidAge] = Field(default_factory=list)
|
||||
|
||||
@field_validator("Stammdaten_rueckkehrer", mode="before")
|
||||
@classmethod
|
||||
def str_to_bool(cls, value: Any) -> Any:
|
||||
if isinstance(value, str):
|
||||
value = value.strip().lower()
|
||||
|
||||
if value == "ja":
|
||||
return True
|
||||
elif value == "nein":
|
||||
return False
|
||||
|
||||
raise ValueError("Wert muss 'ja', 'nein', True oder False sein.")
|
||||
|
||||
return value
|
||||
|
||||
|
||||
class CompanyForm_Search(QWidget):
|
||||
@@ -302,6 +435,7 @@ class FormFieldType(enum.StrEnum):
|
||||
DROPDOWN = enum.auto()
|
||||
EXTENDED_DROPDOWN = enum.auto()
|
||||
DYNAMIC_LIST = enum.auto()
|
||||
DYNAMIC_DROPDOWN = enum.auto()
|
||||
|
||||
|
||||
@dc.dataclass(slots=True)
|
||||
@@ -334,6 +468,7 @@ class FormField:
|
||||
dropdown_options: Sequence[DropdownOption] = dc.field(default=tuple(), init=False)
|
||||
key: str = ""
|
||||
tooltip: str = ""
|
||||
init_label: str = dc.field(init=False)
|
||||
|
||||
def __post_init__(
|
||||
self,
|
||||
@@ -343,6 +478,7 @@ class FormField:
|
||||
self.key = str(uuid.uuid4())
|
||||
|
||||
self.label = self.label.strip()
|
||||
self.init_label = self.label.replace("*", "").replace(":", "")
|
||||
if not self.label.endswith(":") and self.type is not FormFieldType.GROUP:
|
||||
self.label += ":"
|
||||
if self.required:
|
||||
@@ -361,6 +497,32 @@ class FormField:
|
||||
for child in self.children:
|
||||
child.parent = self
|
||||
|
||||
def enhanced_label(
|
||||
self,
|
||||
add_text: str,
|
||||
) -> str:
|
||||
enhanced_label = self.init_label + f" {add_text}"
|
||||
if not enhanced_label.endswith(":") and self.type is not FormFieldType.GROUP:
|
||||
enhanced_label += ":"
|
||||
if self.required:
|
||||
enhanced_label += "*"
|
||||
|
||||
return enhanced_label
|
||||
|
||||
|
||||
def enhanced_label(
|
||||
base_label: str,
|
||||
add_text: str,
|
||||
add_colon: bool = False,
|
||||
) -> str:
|
||||
label = base_label.strip().replace("*", "").replace(":", "")
|
||||
if add_text:
|
||||
label = label + f" {add_text}"
|
||||
if add_colon and not label.endswith(":"):
|
||||
label += ":"
|
||||
|
||||
return label
|
||||
|
||||
|
||||
class WidgetRegistryEntry(TypedDict):
|
||||
widget: QWidget
|
||||
@@ -475,7 +637,7 @@ FORM_FIELDS_CONTACT_PERSON = [
|
||||
FormField(
|
||||
"Name Unternehmen/Netzwerkpartner (pre-filled von Suche)",
|
||||
FormFieldType.TEXT,
|
||||
key="t1",
|
||||
key="KP_name_partner",
|
||||
required=False,
|
||||
placeholder="Text wird nach gewähltem Unternehmen angezeigt",
|
||||
readonly=True,
|
||||
@@ -483,7 +645,7 @@ FORM_FIELDS_CONTACT_PERSON = [
|
||||
FormField(
|
||||
"Titel",
|
||||
FormFieldType.TEXT,
|
||||
key="t2",
|
||||
key="KP_titel",
|
||||
required=False,
|
||||
tooltip=(
|
||||
"* nur wenn anrufende Person oder kontaktaufnehmende Person "
|
||||
@@ -493,49 +655,49 @@ FORM_FIELDS_CONTACT_PERSON = [
|
||||
FormField(
|
||||
"Anrede_Anschrift",
|
||||
FormFieldType.TEXT,
|
||||
key="t3",
|
||||
key="KP_anrede_anschrift",
|
||||
required=True,
|
||||
),
|
||||
FormField(
|
||||
"Name",
|
||||
FormFieldType.TEXT,
|
||||
key="t4",
|
||||
key="KP_name",
|
||||
required=True,
|
||||
),
|
||||
FormField(
|
||||
"Vorname",
|
||||
FormFieldType.TEXT,
|
||||
key="t5",
|
||||
key="KP_vorname",
|
||||
required=False,
|
||||
),
|
||||
FormField(
|
||||
"Festnetznummer",
|
||||
FormFieldType.TEXT,
|
||||
key="t6",
|
||||
key="KP_festnetznummer",
|
||||
required=False,
|
||||
),
|
||||
FormField(
|
||||
"Mobilfunknummer",
|
||||
FormFieldType.TEXT,
|
||||
key="t7",
|
||||
key="KP_mobilfunknummer",
|
||||
required=False,
|
||||
),
|
||||
FormField(
|
||||
"E-Mail",
|
||||
FormFieldType.TEXT,
|
||||
key="t8",
|
||||
key="KP_email",
|
||||
required=False,
|
||||
),
|
||||
FormField(
|
||||
"Funktion/Beziehung zur beratenden Person",
|
||||
FormFieldType.TEXT,
|
||||
key="t9",
|
||||
key="KP_funktion_beziehung",
|
||||
required=False,
|
||||
),
|
||||
FormField(
|
||||
"Adresse",
|
||||
FormFieldType.LONGTEXT,
|
||||
key="t10",
|
||||
key="KP_adresse",
|
||||
required=False,
|
||||
),
|
||||
]
|
||||
@@ -544,6 +706,7 @@ FORM_FIELDS_MASTER_DATA = [
|
||||
FormField(
|
||||
"Titel",
|
||||
FormFieldType.TEXT,
|
||||
key="Stammdaten_titel",
|
||||
required=False,
|
||||
tooltip=(
|
||||
"* nur wenn anrufende Person oder kontaktaufnehmende Person "
|
||||
@@ -553,21 +716,25 @@ FORM_FIELDS_MASTER_DATA = [
|
||||
FormField(
|
||||
"Anrede",
|
||||
FormFieldType.TEXT,
|
||||
key="Stammdaten_anrede_anschrift",
|
||||
required=True,
|
||||
),
|
||||
FormField(
|
||||
"Name",
|
||||
FormFieldType.TEXT,
|
||||
key="Stammdaten_name",
|
||||
required=True,
|
||||
),
|
||||
FormField(
|
||||
"Vorname",
|
||||
FormFieldType.TEXT,
|
||||
key="Stammdaten_vorname",
|
||||
required=False,
|
||||
),
|
||||
FormField(
|
||||
"Geburtsdatum",
|
||||
FormFieldType.DATE,
|
||||
key="Stammdaten_geburtsdatum",
|
||||
required=False,
|
||||
tooltip=(
|
||||
"* Wichtig zu erfragen, da u.a. Mindestgehaltsschwelle davon abhängt "
|
||||
@@ -576,21 +743,26 @@ FORM_FIELDS_MASTER_DATA = [
|
||||
),
|
||||
FormField(
|
||||
"Herkunftsland",
|
||||
FormFieldType.DROPDOWN,
|
||||
FormFieldType.EXTENDED_DROPDOWN,
|
||||
key="Stammdaten_herkunftsland",
|
||||
required=True,
|
||||
options=[("LÄNDERLISTE NOCH ZU ERGÄNZEN", None)],
|
||||
placeholder="Suche...",
|
||||
options=COUNTRY_LIST.for_dropdown,
|
||||
tooltip=("* Wichtig zu erfragen aufgrund eventueller EU-Freizügigkeitsregelung"),
|
||||
),
|
||||
FormField(
|
||||
"Staatsangehörigkeit",
|
||||
FormFieldType.DROPDOWN,
|
||||
FormFieldType.EXTENDED_DROPDOWN,
|
||||
key="Stammdaten_herkunftsland",
|
||||
required=False,
|
||||
options=[("LÄNDERLISTE NOCH ZU ERGÄNZEN", None)],
|
||||
placeholder="Suche...",
|
||||
options=COUNTRY_LIST.for_dropdown,
|
||||
tooltip=("* Wichtig zu erfragen aufgrund eventueller EU-Freizügigkeitsregelung"),
|
||||
),
|
||||
FormField(
|
||||
"Rückkehrer",
|
||||
FormFieldType.DROPDOWN,
|
||||
key="Stammdaten_rueckkehrer",
|
||||
required=False,
|
||||
options=[("ja", None), ("nein", None)],
|
||||
tooltip=("* Wichtig zu erfragen aufgrund eventueller EU-Freizügigkeitsregelung"),
|
||||
@@ -598,34 +770,40 @@ FORM_FIELDS_MASTER_DATA = [
|
||||
FormField(
|
||||
"Wo befindet sich die Person?",
|
||||
FormFieldType.DROPDOWN,
|
||||
key="Stammdaten_aufenthaltsort",
|
||||
required=True,
|
||||
options=[("Inland", None), ("Ausland EU/EWR", None), ("Ausland Drittstaat", None)],
|
||||
),
|
||||
FormField(
|
||||
"Straße",
|
||||
FormFieldType.TEXT,
|
||||
key="Stammdaten_strasse",
|
||||
required=False,
|
||||
),
|
||||
FormField(
|
||||
"Hausnummer",
|
||||
FormFieldType.TEXT,
|
||||
key="Stammdaten_hausnummer",
|
||||
required=False,
|
||||
),
|
||||
FormField(
|
||||
"PLZ",
|
||||
FormFieldType.TEXT,
|
||||
key="Stammdaten_PLZ",
|
||||
required=False,
|
||||
),
|
||||
FormField(
|
||||
"Ort",
|
||||
FormFieldType.TEXT,
|
||||
key="Stammdaten_ort",
|
||||
required=False,
|
||||
),
|
||||
FormField(
|
||||
"Bundesland",
|
||||
FormFieldType.DROPDOWN,
|
||||
key="Stammdaten_bundesland",
|
||||
required=False,
|
||||
options=[("BUNDESLÄNDER NOCH ZU ERGÄNZEN", None)],
|
||||
options=GERMAN_STATE_LIST.for_dropdown,
|
||||
tooltip=(
|
||||
"nur wenn Inland angegeben und die Angabe zieht es in keine Dokumente "
|
||||
"rüber! Liste Bundesländer verwenden"
|
||||
@@ -634,35 +812,63 @@ FORM_FIELDS_MASTER_DATA = [
|
||||
FormField(
|
||||
"Land",
|
||||
FormFieldType.TEXT,
|
||||
key="Stammdaten_land",
|
||||
required=False,
|
||||
),
|
||||
FormField(
|
||||
"Festnetznummer",
|
||||
FormFieldType.TEXT,
|
||||
key="Stammdaten_festnetznummer",
|
||||
required=False,
|
||||
),
|
||||
FormField(
|
||||
"Mobilfunknummer",
|
||||
FormFieldType.TEXT,
|
||||
key="Stammdaten_mobilfunknummer",
|
||||
required=False,
|
||||
),
|
||||
FormField(
|
||||
"E-Mail",
|
||||
FormFieldType.TEXT,
|
||||
key="Stammdaten_email",
|
||||
required=False,
|
||||
),
|
||||
FormField(
|
||||
"Familienstand",
|
||||
FormFieldType.TEXT,
|
||||
key="Stammdaten_familienstand",
|
||||
required=False,
|
||||
tooltip="* Wichtig zu erfragen aufgrund Lebensunterhaltssicherung",
|
||||
),
|
||||
# FormField(
|
||||
# "Anzahl Kinder",
|
||||
# FormFieldType.DYNAMIC_DROPDOWN,
|
||||
# key="Stammdaten_anzahl_kinder",
|
||||
# required=False,
|
||||
# options=[(str(x), None) for x in range(11)],
|
||||
# tooltip="* Wichtig zu erfragen aufgrund Lebensunterhaltssicherung",
|
||||
# ),
|
||||
FormField(
|
||||
"Anzahl Kinder",
|
||||
FormFieldType.DROPDOWN,
|
||||
FormFieldType.DYNAMIC_DROPDOWN,
|
||||
required=False,
|
||||
options=[(str(x), None) for x in range(11)],
|
||||
tooltip="* Wichtig zu erfragen aufgrund Lebensunterhaltssicherung",
|
||||
key="Stammdaten_anzahl_kinder",
|
||||
children=[
|
||||
FormField(
|
||||
"Anzahl Kinder",
|
||||
FormFieldType.DROPDOWN,
|
||||
required=False,
|
||||
options=[(str(x), None) for x in range(11)],
|
||||
tooltip="* Wichtig zu erfragen aufgrund Lebensunterhaltssicherung",
|
||||
key="Stammdaten_anzahl_kinder",
|
||||
children=[
|
||||
FormField(
|
||||
"Alter Kind", FormFieldType.TEXT, key="Stammdaten_alter_kinder"
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
@@ -736,25 +942,21 @@ FORM_FIELDS_ADDITIONAL_DATA = [
|
||||
]
|
||||
|
||||
FORM_FIELDS_SCHOOL = [
|
||||
FormField("Abschluss", FormFieldType.TEXT, required=False, key="abschluss"),
|
||||
FormField(
|
||||
"Abschluss",
|
||||
FormFieldType.TEXT,
|
||||
required=True,
|
||||
),
|
||||
FormField(
|
||||
"Abschlussgrad laut Dokument",
|
||||
FormFieldType.TEXT,
|
||||
required=False,
|
||||
"Abschlussgrad laut Dokument", FormFieldType.TEXT, required=False, key="abschlussgrad"
|
||||
),
|
||||
FormField(
|
||||
"Schule",
|
||||
FormFieldType.TEXT,
|
||||
required=False,
|
||||
key="schule",
|
||||
),
|
||||
FormField(
|
||||
"Ort",
|
||||
FormFieldType.TEXT,
|
||||
required=False,
|
||||
key="ort",
|
||||
),
|
||||
FormField(
|
||||
"Land",
|
||||
@@ -764,15 +966,12 @@ FORM_FIELDS_SCHOOL = [
|
||||
placeholder="Suche...",
|
||||
options=COUNTRY_LIST.for_dropdown,
|
||||
),
|
||||
FormField(
|
||||
"Abschlussjahr",
|
||||
FormFieldType.TEXT,
|
||||
required=False,
|
||||
),
|
||||
FormField("Abschlussjahr", FormFieldType.TEXT, required=False, key="abschlussjahr"),
|
||||
FormField(
|
||||
"Bemerkungsfeld",
|
||||
FormFieldType.TEXT,
|
||||
required=False,
|
||||
key="bemerkung",
|
||||
),
|
||||
]
|
||||
|
||||
@@ -946,12 +1145,12 @@ FORM_FIELDS = [
|
||||
FormField(
|
||||
"Status && Projektrelevanz",
|
||||
FormFieldType.GROUP,
|
||||
key="state_relevance",
|
||||
key="Projektrelevanz",
|
||||
children=[
|
||||
FormField(
|
||||
"Projektrelevanz",
|
||||
FormFieldType.DROPDOWN,
|
||||
key="projektrelevanz",
|
||||
key="Projektrelevanz_relevanz",
|
||||
required=True,
|
||||
options=[("ja", None), ("nein", None)],
|
||||
),
|
||||
@@ -960,30 +1159,57 @@ FORM_FIELDS = [
|
||||
FormField(
|
||||
"Daten Kontaktperson",
|
||||
FormFieldType.GROUP,
|
||||
key="data_contact_person",
|
||||
key="Kontaktperson",
|
||||
children=FORM_FIELDS_CONTACT_PERSON,
|
||||
),
|
||||
FormField(
|
||||
"Stammdaten",
|
||||
FormFieldType.GROUP,
|
||||
key="Stammdaten",
|
||||
children=FORM_FIELDS_MASTER_DATA,
|
||||
),
|
||||
FormField(
|
||||
"Schulbildung",
|
||||
FormFieldType.DYNAMIC_LIST,
|
||||
children=FORM_FIELDS_SCHOOL,
|
||||
key="Schulbildung",
|
||||
),
|
||||
FormField(
|
||||
"Test Länderauswahl",
|
||||
FormFieldType.GROUP,
|
||||
key="countries",
|
||||
children=[
|
||||
FormField(
|
||||
"Länderauswahl",
|
||||
FormFieldType.EXTENDED_DROPDOWN,
|
||||
key="country",
|
||||
required=True,
|
||||
placeholder="Suche...",
|
||||
options=COUNTRY_LIST.for_dropdown,
|
||||
),
|
||||
],
|
||||
),
|
||||
# FormField(
|
||||
# "Test Länderauswahl",
|
||||
# FormFieldType.GROUP,
|
||||
# key="countries",
|
||||
# children=[
|
||||
# FormField(
|
||||
# "Länderauswahl",
|
||||
# FormFieldType.EXTENDED_DROPDOWN,
|
||||
# key="country",
|
||||
# required=True,
|
||||
# placeholder="Suche...",
|
||||
# options=COUNTRY_LIST.for_dropdown,
|
||||
# ),
|
||||
# ],
|
||||
# ),
|
||||
# FormField(
|
||||
# "Anzahl Kinder (dynamischer Dropdown)",
|
||||
# FormFieldType.DYNAMIC_DROPDOWN,
|
||||
# required=False,
|
||||
# options=[(str(x), None) for x in range(11)],
|
||||
# tooltip="* Wichtig zu erfragen aufgrund Lebensunterhaltssicherung",
|
||||
# key="DynamicDropdown",
|
||||
# children=[
|
||||
# FormField(
|
||||
# "Anzahl Kinder",
|
||||
# FormFieldType.DROPDOWN,
|
||||
# required=False,
|
||||
# options=[(str(x), None) for x in range(11)],
|
||||
# tooltip="* Wichtig zu erfragen aufgrund Lebensunterhaltssicherung",
|
||||
# key="MainDropdown",
|
||||
# children=[
|
||||
# FormField("Alter Kind", FormFieldType.TEXT),
|
||||
# ],
|
||||
# ),
|
||||
# ],
|
||||
# ),
|
||||
# FormFieldGroup("Daten Kontaktperson", FORM_FIELDS_CONTACT_PERSON),
|
||||
# FormFieldGroup("Stammdaten (ERGÄNZUNG KINDERALTER DYNAMISCH)", FORM_FIELDS_MASTER_DATA),
|
||||
# FormFieldGroup("weitere Informationen", FORM_FIELDS_ADDITIONAL_DATA),
|
||||
@@ -1184,6 +1410,18 @@ def _build_ui_recursively(
|
||||
}
|
||||
parent_layout.addRow(widget)
|
||||
|
||||
case FormFieldType.DYNAMIC_DROPDOWN:
|
||||
widget = DynamicDropdownWidget(
|
||||
field.children,
|
||||
field.label,
|
||||
prefix=f"{full_key}",
|
||||
)
|
||||
widget_registry[full_key] = {
|
||||
"widget": widget,
|
||||
"form_field": field,
|
||||
}
|
||||
parent_layout.addRow(widget)
|
||||
|
||||
case _:
|
||||
raise NotImplementedError(f"Not supported field type: {field.type.value}")
|
||||
|
||||
@@ -1240,6 +1478,9 @@ def reset_form(
|
||||
elif isinstance(widget, DynamicListWidget):
|
||||
# dynamic list widget manages its widgets by itself
|
||||
widget.reset_form()
|
||||
elif isinstance(widget, DynamicDropdownWidget):
|
||||
# dynamic list widget manages its widgets by itself
|
||||
widget.reset_form()
|
||||
|
||||
widget.setStyleSheet("")
|
||||
|
||||
@@ -1255,6 +1496,31 @@ def _insert_nested(
|
||||
target_dict[key_path[-1]] = value
|
||||
|
||||
|
||||
def update_sub_forms(
|
||||
widget_registry: WidgetRegistry,
|
||||
sub_forms: Sequence[SubForm],
|
||||
base_label: str = "",
|
||||
):
|
||||
total_num_sub_forms = len(sub_forms)
|
||||
for index, sub_form in enumerate(sub_forms, start=1):
|
||||
if isinstance(sub_form.entry_box, QGroupBox) and base_label:
|
||||
sub_form.entry_box.setTitle(f"{base_label} {index}")
|
||||
change_sub_form_widget_registry(
|
||||
widget_registry,
|
||||
sub_form,
|
||||
index,
|
||||
)
|
||||
|
||||
for key in tuple(widget_registry.keys()):
|
||||
matches = DYNAMIC_LIST_KEY_PATTERN.search(key)
|
||||
if not matches:
|
||||
continue
|
||||
|
||||
counter_sub_form = int(matches.group(1))
|
||||
if counter_sub_form > total_num_sub_forms:
|
||||
del widget_registry[key]
|
||||
|
||||
|
||||
def get_form_data(
|
||||
widget_registry: WidgetRegistry,
|
||||
) -> dict[str, Any]:
|
||||
@@ -1277,6 +1543,15 @@ def get_form_data(
|
||||
# of such dictionaries
|
||||
form_data = widget.get_form_data()
|
||||
value = [val for val in form_data.values()]
|
||||
# print(">>>>>>>>> Form Data:")
|
||||
# pprint(form_data)
|
||||
elif isinstance(widget, DynamicDropdownWidget):
|
||||
# this should be a list: each dynamic list contains a list
|
||||
# of such dictionaries
|
||||
form_data = widget.get_form_data()
|
||||
value = [val for val in form_data.values()]
|
||||
# print(">>>>>>>>> Form Data:")
|
||||
# pprint(form_data)
|
||||
|
||||
_insert_nested(raw_data, key.split("."), value)
|
||||
|
||||
@@ -1459,6 +1734,16 @@ class AutoForm(QWidget):
|
||||
print("Erfolg! Alle Daten sind valide.")
|
||||
print("Get form data call...")
|
||||
form_data = self.get_form_data()
|
||||
post_proc_1 = form_data["Stammdaten"]["Stammdaten_anzahl_kinder"]
|
||||
|
||||
Stammdaten_anzahl_kinder = post_proc_1[0]["Stammdaten_anzahl_kinder-[0]"][
|
||||
"'Stammdaten_anzahl_kinder'"
|
||||
]
|
||||
Stammdaten_alter_kinder: list[str] = []
|
||||
if len(post_proc_1) > 1:
|
||||
for i in range(1, len(post_proc_1)):
|
||||
content = post_proc_1[i]
|
||||
|
||||
print("------------>>>>>>>>> Get form data")
|
||||
pprint(form_data)
|
||||
# ------------------------------------------------------------
|
||||
@@ -1478,7 +1763,7 @@ class AutoForm(QWidget):
|
||||
|
||||
@dc.dataclass(slots=True)
|
||||
class SubForm:
|
||||
entry_box: QGroupBox
|
||||
entry_box: QWidget
|
||||
prefix_parent: str
|
||||
index: int
|
||||
prefix: str = ""
|
||||
@@ -1529,6 +1814,7 @@ class DynamicListWidget(QWidget):
|
||||
super().__init__()
|
||||
self.form_fields = form_fields
|
||||
self.label = label
|
||||
self.base_label = enhanced_label(label, add_text="")
|
||||
self.prefix = prefix
|
||||
self.widget_registry: WidgetRegistry = {}
|
||||
|
||||
@@ -1551,6 +1837,8 @@ class DynamicListWidget(QWidget):
|
||||
|
||||
self.inner_layout.addWidget(self.add_btn)
|
||||
|
||||
self.widget_registry_base_size = len(self.widget_registry)
|
||||
|
||||
# add empty sub form as initial value
|
||||
self.add_entry()
|
||||
|
||||
@@ -1590,13 +1878,13 @@ class DynamicListWidget(QWidget):
|
||||
self.update_sub_forms()
|
||||
|
||||
def update_sub_forms(self):
|
||||
for index, sub_form in enumerate(self.sub_forms, start=1):
|
||||
sub_form.entry_box.setTitle(f"{self.label} {index}")
|
||||
change_sub_form_widget_registry(
|
||||
self.widget_registry,
|
||||
sub_form,
|
||||
index,
|
||||
)
|
||||
update_sub_forms(
|
||||
self.widget_registry,
|
||||
sub_forms=self.sub_forms,
|
||||
base_label=self.base_label,
|
||||
)
|
||||
|
||||
# pprint_registry(self.widget_registry)
|
||||
|
||||
def reset_form(self) -> None:
|
||||
reset_form(self.widget_registry)
|
||||
@@ -1614,6 +1902,146 @@ class DynamicListWidget(QWidget):
|
||||
return raw_data
|
||||
|
||||
|
||||
class DynamicDropdownWidget(QWidget):
|
||||
"""
|
||||
A Widget, which can generate and manage an arbitrary number of sub forms with additional
|
||||
information on a combobox selection (integer in combobox).
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
form_fields: Sequence[FormField],
|
||||
label_add_info: str = "Eintrag",
|
||||
prefix: str = "",
|
||||
):
|
||||
super().__init__()
|
||||
|
||||
# form_fields = form_fields.children
|
||||
if len(form_fields) == 0 or len(form_fields) > 1:
|
||||
raise ValueError(
|
||||
"Dynamic Dropdown Widget must have only one child, which is a dropdown widget"
|
||||
)
|
||||
|
||||
self.combobox_field = form_fields[0]
|
||||
assigned_form_fields = self.combobox_field.children
|
||||
if len(assigned_form_fields) == 0 or len(assigned_form_fields) > 1:
|
||||
raise ValueError(
|
||||
(
|
||||
"Dynamic Dropdown Widget's dropdown element must have only one "
|
||||
"child, which is a single field definition"
|
||||
)
|
||||
)
|
||||
|
||||
self.assigned_form_field = assigned_form_fields[0]
|
||||
|
||||
self.label_add_info = label_add_info
|
||||
self.prefix = prefix
|
||||
self.widget_registry: WidgetRegistry = {}
|
||||
|
||||
# layout for group component
|
||||
# self.group_box = QGroupBox(label)
|
||||
self.main_layout = QVBoxLayout(self)
|
||||
self.main_layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.form_layout = QFormLayout()
|
||||
self.main_layout.addLayout(self.form_layout)
|
||||
|
||||
_build_ui_recursively(
|
||||
[self.combobox_field],
|
||||
self.form_layout,
|
||||
self.widget_registry,
|
||||
prefix=f"{self.prefix}-[0]",
|
||||
)
|
||||
dropdown_widget_entry = tuple(self.widget_registry.values())[0]
|
||||
dropdown_widget = dropdown_widget_entry["widget"]
|
||||
assert isinstance(dropdown_widget, QComboBox)
|
||||
self.dropdown_widget = dropdown_widget
|
||||
|
||||
self.rows_container = QWidget()
|
||||
self.rows_layout = QVBoxLayout(self.rows_container)
|
||||
self.rows_layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.main_layout.addWidget(self.rows_container)
|
||||
|
||||
self.sub_forms: list[SubForm] = []
|
||||
|
||||
self.dropdown_widget.currentTextChanged.connect(self.on_anzahl_changed)
|
||||
self.widget_registry_base_size = len(self.widget_registry)
|
||||
|
||||
def on_anzahl_changed(
|
||||
self,
|
||||
text: str,
|
||||
) -> None:
|
||||
target_count: int
|
||||
if text == DROPDOWN_DEFAULT:
|
||||
target_count = 0
|
||||
else:
|
||||
target_count = int(text)
|
||||
current_count = len(self.sub_forms)
|
||||
|
||||
if target_count > current_count:
|
||||
differenz = target_count - current_count
|
||||
for _ in range(differenz):
|
||||
self._add_row()
|
||||
|
||||
elif target_count < current_count:
|
||||
differenz = current_count - target_count
|
||||
for _ in range(differenz):
|
||||
self._remove_row()
|
||||
|
||||
def _add_row(self) -> None:
|
||||
number_form = len(self.sub_forms) + 1
|
||||
container = QWidget()
|
||||
container.setContentsMargins(0, 0, 0, 0)
|
||||
form_layout = QFormLayout(container)
|
||||
form_layout.setContentsMargins(10, 0, 0, 0)
|
||||
sub_form = SubForm(container, prefix_parent=self.prefix, index=number_form)
|
||||
|
||||
form_field_def = copy.copy(self.assigned_form_field)
|
||||
form_field_def.label = form_field_def.enhanced_label(f"{number_form}")
|
||||
|
||||
_build_ui_recursively(
|
||||
schema=[form_field_def],
|
||||
parent_layout=form_layout,
|
||||
widget_registry=self.widget_registry,
|
||||
prefix=f"{self.prefix}-[{number_form}]",
|
||||
)
|
||||
self.rows_layout.addWidget(container)
|
||||
|
||||
self.sub_forms.append(sub_form)
|
||||
self.update_sub_forms()
|
||||
|
||||
def _remove_row(self) -> None:
|
||||
last_form = self.sub_forms.pop()
|
||||
box_to_remove = last_form.entry_box
|
||||
|
||||
self.rows_layout.removeWidget(box_to_remove)
|
||||
box_to_remove.deleteLater()
|
||||
self.update_sub_forms()
|
||||
|
||||
def update_sub_forms(self) -> None:
|
||||
update_sub_forms(
|
||||
self.widget_registry,
|
||||
sub_forms=self.sub_forms,
|
||||
)
|
||||
|
||||
# pprint_registry(self.widget_registry)
|
||||
|
||||
def reset_form(self) -> None:
|
||||
# resets dynamic content when dropdown is set back to default value
|
||||
self.dropdown_widget.setCurrentIndex(0)
|
||||
|
||||
def validate_form_data(self) -> list[str]:
|
||||
return validate_form_data(self.widget_registry)
|
||||
|
||||
def load_form_data(self) -> None:
|
||||
# TODO add way to load data when initialised (probably with click)
|
||||
...
|
||||
|
||||
def get_form_data(self):
|
||||
raw_data = get_form_data(self.widget_registry)
|
||||
|
||||
return raw_data
|
||||
|
||||
|
||||
class ClickableCell(QFrame):
|
||||
"""cell in the table on the startup screen"""
|
||||
|
||||
|
||||
@@ -3,10 +3,74 @@ import dataclasses as dc
|
||||
import enum
|
||||
import re
|
||||
from collections.abc import Sequence
|
||||
from typing import Any
|
||||
|
||||
import babel
|
||||
from PySide6.QtCore import QDate, Qt
|
||||
|
||||
# %%
|
||||
DYNAMIC_LIST_KEY_PATTERN = re.compile(r"-\[(\d+)\]")
|
||||
|
||||
dynamic_content = {
|
||||
"Stammdaten_anzahl_kinder-[0]": {"Stammdaten_anzahl_kinder": "5"},
|
||||
"Stammdaten_anzahl_kinder-[1]": {"Stammdaten_alter_kinder": "23213"},
|
||||
"Stammdaten_anzahl_kinder-[2]": {"Stammdaten_alter_kinder": "123123"},
|
||||
"Stammdaten_anzahl_kinder-[3]": {"Stammdaten_alter_kinder": "123213"},
|
||||
"Stammdaten_anzahl_kinder-[4]": {"Stammdaten_alter_kinder": "123123"},
|
||||
"Stammdaten_anzahl_kinder-[5]": {"Stammdaten_alter_kinder": "123123"},
|
||||
}
|
||||
|
||||
|
||||
def find_dynamic_content(content: dict[str, Any]) -> dict[str, Any] | None:
|
||||
|
||||
found = None
|
||||
for key in dynamic_content.keys():
|
||||
if DYNAMIC_LIST_KEY_PATTERN.search(key):
|
||||
# found an match: this is dynamic content dictionary
|
||||
print("found")
|
||||
found = dynamic_content
|
||||
break
|
||||
|
||||
return found
|
||||
|
||||
|
||||
# %%
|
||||
new_content = {
|
||||
"Stammdaten": {
|
||||
"Stammdaten_PLZ": "",
|
||||
"Stammdaten_anrede_anschrift": "asdasdas",
|
||||
"Stammdaten_anzahl_kinder": [
|
||||
{
|
||||
"Stammdaten_anzahl_kinder-[0]": {"Stammdaten_anzahl_kinder": "5"},
|
||||
"Stammdaten_anzahl_kinder-[1]": {"Stammdaten_alter_kinder": "23213"},
|
||||
"Stammdaten_anzahl_kinder-[2]": {"Stammdaten_alter_kinder": "123123"},
|
||||
"Stammdaten_anzahl_kinder-[3]": {"Stammdaten_alter_kinder": "123213"},
|
||||
"Stammdaten_anzahl_kinder-[4]": {"Stammdaten_alter_kinder": "123123"},
|
||||
"Stammdaten_anzahl_kinder-[5]": {"Stammdaten_alter_kinder": "123123"},
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def flat_dict(contents):
|
||||
for x in contents:
|
||||
if isinstance(contents, dict):
|
||||
yield from flat_dict(tuple(contents[x]))
|
||||
elif isinstance(x, (list, tuple, set)):
|
||||
yield from flat_dict(x)
|
||||
else:
|
||||
yield x
|
||||
|
||||
|
||||
# %%
|
||||
for x in flat_dict(new_content):
|
||||
print(x)
|
||||
|
||||
|
||||
# %%
|
||||
find_dynamic_content(dynamic_content)
|
||||
|
||||
|
||||
# %%
|
||||
@dc.dataclass(slots=True)
|
||||
|
||||
Reference in New Issue
Block a user