added list of countries

This commit is contained in:
2026-05-13 12:45:45 +02:00
parent a7accaa20c
commit 2931bf0876
4 changed files with 187 additions and 38 deletions

4
pdm.lock generated
View File

@@ -5,7 +5,7 @@
groups = ["default", "dev", "lint", "nb", "tests"] groups = ["default", "dev", "lint", "nb", "tests"]
strategy = ["inherit_metadata"] strategy = ["inherit_metadata"]
lock_version = "4.5.0" lock_version = "4.5.0"
content_hash = "sha256:09d959f153789f965fe2d45e1eb65842eb8d0b446b67cdec76891c6048192b0c" content_hash = "sha256:ae1cefda69bbf1f63d7c5d8c8b19f5dae8525f42c8550e9a44b186d7f57fe7bc"
[[metadata.targets]] [[metadata.targets]]
requires_python = ">=3.11,<3.14" requires_python = ">=3.11,<3.14"
@@ -321,7 +321,7 @@ name = "babel"
version = "2.18.0" version = "2.18.0"
requires_python = ">=3.8" requires_python = ">=3.8"
summary = "Internationalization utilities" summary = "Internationalization utilities"
groups = ["nb"] groups = ["default", "nb"]
dependencies = [ dependencies = [
"pytz>=2015.7; python_version < \"3.9\"", "pytz>=2015.7; python_version < \"3.9\"",
] ]

View File

@@ -10,6 +10,7 @@ from collections.abc import Sequence
from pprint import pprint from pprint import pprint
from typing import Any, Protocol, TypeAlias, TypedDict from typing import Any, Protocol, TypeAlias, TypedDict
import babel
from PySide6.QtCore import QDate, QModelIndex, QStringListModel, Qt, QTimer, Signal from PySide6.QtCore import QDate, QModelIndex, QStringListModel, Qt, QTimer, Signal
from PySide6.QtGui import QAction, QStandardItem, QStandardItemModel from PySide6.QtGui import QAction, QStandardItem, QStandardItemModel
from PySide6.QtWidgets import ( from PySide6.QtWidgets import (
@@ -55,6 +56,34 @@ QSS = """
} }
""" """
DROPDOWN_DEFAULT: str = "--- Bitte wählen ---" DROPDOWN_DEFAULT: str = "--- Bitte wählen ---"
DYNAMIC_LIST_KEY_PATTERN = re.compile(r"-\[(\d+)\]")
@dc.dataclass(slots=True)
class CountryList:
iso_to_country: dict[str, str]
for_dropdown: Sequence[tuple[str, str]]
def get_country_list_german() -> CountryList:
locale = babel.Locale("de", "DE")
countries: list[tuple[str, str]] = []
iso_to_country: dict[str, str] = {}
for iso_code, country_name in locale.territories.items():
if len(iso_code) == 2 and not iso_code.isdigit():
countries.append((country_name, iso_code))
iso_to_country[iso_code] = country_name
countries.sort(key=lambda x: x[0])
return CountryList(
iso_to_country=iso_to_country,
for_dropdown=tuple(countries),
)
COUNTRY_LIST = get_country_list_german()
class CompanyForm_Search(QWidget): class CompanyForm_Search(QWidget):
@@ -166,7 +195,8 @@ class ContactPersonForm_Search(QWidget):
title.setStyleSheet("font-size: 14px; font-style: italic;") # font-weight: bold; title.setStyleSheet("font-size: 14px; font-style: italic;") # font-weight: bold;
main_layout.addWidget(title) main_layout.addWidget(title)
# --- SEARCH --- # --- SEARCH ---
self.search_input = QComboBox(placeholderText="Tippen zum Suchen...") # self.search_input = QComboBox(placeholderText="Tippen zum Suchen...")
self.search_input = QComboBox()
self.search_input.setEditable(True) self.search_input.setEditable(True)
self.search_input.setInsertPolicy(QComboBox.InsertPolicy.NoInsert) self.search_input.setInsertPolicy(QComboBox.InsertPolicy.NoInsert)
line_edit = self.search_input.lineEdit() line_edit = self.search_input.lineEdit()
@@ -270,6 +300,7 @@ class FormFieldType(enum.StrEnum):
DATE = enum.auto() DATE = enum.auto()
DATETIME = enum.auto() DATETIME = enum.auto()
DROPDOWN = enum.auto() DROPDOWN = enum.auto()
EXTENDED_DROPDOWN = enum.auto()
DYNAMIC_LIST = enum.auto() DYNAMIC_LIST = enum.auto()
@@ -285,6 +316,8 @@ class DropdownOption:
) -> None: ) -> None:
if _data is None: if _data is None:
self.data = self.label self.data = self.label
else:
self.data = _data
@dc.dataclass(slots=True) @dc.dataclass(slots=True)
@@ -315,9 +348,12 @@ class FormField:
if self.required: if self.required:
self.label += "*" self.label += "*"
if self.type is FormFieldType.DROPDOWN and not options: if (
self.type in (FormFieldType.DROPDOWN, FormFieldType.EXTENDED_DROPDOWN)
and not options
):
raise ValueError("Invalid field definition: Dropdown requires options") raise ValueError("Invalid field definition: Dropdown requires options")
elif self.type is FormFieldType.DROPDOWN: elif self.type in (FormFieldType.DROPDOWN, FormFieldType.EXTENDED_DROPDOWN):
self.dropdown_options = tuple(DropdownOption(op[0], op[1]) for op in options) self.dropdown_options = tuple(DropdownOption(op[0], op[1]) for op in options)
if self.children: if self.children:
@@ -722,9 +758,11 @@ FORM_FIELDS_SCHOOL = [
), ),
FormField( FormField(
"Land", "Land",
FormFieldType.DROPDOWN, FormFieldType.EXTENDED_DROPDOWN,
key="country",
required=False, required=False,
options=[("LÄNDERLISTE ERGÄNZEN", None)], placeholder="Suche...",
options=COUNTRY_LIST.for_dropdown,
), ),
FormField( FormField(
"Abschlussjahr", "Abschlussjahr",
@@ -774,9 +812,11 @@ FORM_FIELDS_HIGHER_EDUCATION = [
), ),
FormField( FormField(
"Land", "Land",
FormFieldType.DROPDOWN, FormFieldType.EXTENDED_DROPDOWN,
key="country",
required=False, required=False,
options=[("LÄNDERLISTE ERGÄNZEN", None)], placeholder="Suche...",
options=COUNTRY_LIST.for_dropdown,
), ),
FormField( FormField(
"Ort", "Ort",
@@ -832,9 +872,11 @@ FORM_FIELDS_WORK_EXPERIENCE = [
), ),
FormField( FormField(
"Land", "Land",
FormFieldType.DROPDOWN, FormFieldType.EXTENDED_DROPDOWN,
key="country",
required=False, required=False,
options=[("LÄNDERLISTE ERGÄNZEN", None)], placeholder="Suche...",
options=COUNTRY_LIST.for_dropdown,
), ),
FormField( FormField(
"Zeitspanne (von ... bis ...)", "Zeitspanne (von ... bis ...)",
@@ -927,6 +969,21 @@ FORM_FIELDS = [
children=FORM_FIELDS_SCHOOL, children=FORM_FIELDS_SCHOOL,
key="Schulbildung", 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,
),
],
),
# FormFieldGroup("Daten Kontaktperson", FORM_FIELDS_CONTACT_PERSON), # FormFieldGroup("Daten Kontaktperson", FORM_FIELDS_CONTACT_PERSON),
# FormFieldGroup("Stammdaten (ERGÄNZUNG KINDERALTER DYNAMISCH)", FORM_FIELDS_MASTER_DATA), # FormFieldGroup("Stammdaten (ERGÄNZUNG KINDERALTER DYNAMISCH)", FORM_FIELDS_MASTER_DATA),
# FormFieldGroup("weitere Informationen", FORM_FIELDS_ADDITIONAL_DATA), # FormFieldGroup("weitere Informationen", FORM_FIELDS_ADDITIONAL_DATA),
@@ -1077,6 +1134,44 @@ def _build_ui_recursively(
else: else:
parent_layout.addRow(field.label, widget) parent_layout.addRow(field.label, widget)
case FormFieldType.EXTENDED_DROPDOWN:
widget = QComboBox()
widget.setEditable(True)
widget.setInsertPolicy(QComboBox.InsertPolicy.NoInsert)
completer = widget.completer()
assert completer
completer.setCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
completer.setFilterMode(Qt.MatchFlag.MatchContains)
completer.setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
assert field.dropdown_options
widget.addItem(DROPDOWN_DEFAULT, None)
for option in field.dropdown_options:
widget.addItem(option.label, option.data)
if field.placeholder:
line_edit = widget.lineEdit()
assert line_edit
line_edit.setPlaceholderText(field.placeholder)
if field.fill_value:
widget.setCurrentText(field.fill_value)
else:
widget.setCurrentIndex(-1)
if field.readonly:
widget.setEnabled(False)
widget.setProperty("styleClass", "stempel")
widget_registry[full_key] = {
"widget": widget,
"form_field": field,
}
if field.tooltip:
tooltip_layout = _add_tooltip(widget, field.tooltip)
parent_layout.addRow(field.label, tooltip_layout)
else:
parent_layout.addRow(field.label, widget)
case FormFieldType.DYNAMIC_LIST: case FormFieldType.DYNAMIC_LIST:
widget = DynamicListWidget( widget = DynamicListWidget(
field.children, field.children,
@@ -1188,9 +1283,6 @@ def get_form_data(
return raw_data return raw_data
DYNAMIC_LIST_KEY_PATTERN = re.compile(r"-\[(\d+)\]")
def validate_form_data( def validate_form_data(
widget_registry: WidgetRegistry, widget_registry: WidgetRegistry,
) -> list[str]: ) -> list[str]:

View File

@@ -2,10 +2,90 @@
import dataclasses as dc import dataclasses as dc
import enum import enum
import re import re
from collections.abc import Sequence
import babel
from PySide6.QtCore import QDate, Qt from PySide6.QtCore import QDate, Qt
# %%
@dc.dataclass(slots=True)
class CountryList:
iso_to_country: dict[str, str]
for_dropdown: Sequence[tuple[str, str]]
def get_country_list_german() -> CountryList:
locale = babel.Locale("de", "DE")
countries: list[tuple[str, str]] = []
iso_to_country: dict[str, str] = {}
for iso_code, country_name in locale.territories.items():
if len(iso_code) == 2 and not iso_code.isdigit():
countries.append((country_name, iso_code))
iso_to_country[iso_code] = country_name
countries.sort(key=lambda x: x[0])
return CountryList(
iso_to_country=iso_to_country,
for_dropdown=tuple(countries),
)
# %%
laender_liste
# %%
DYNAMIC_LIST_KEY_PATTERN = r"-\[(\d+)\]"
key = "Schulbildung-[12].7b8da0f7-7a0e-4f71-878a-85616099e849"
matches = re.search(DYNAMIC_LIST_KEY_PATTERN, key)
# %%
matches
# %%
matches.group(1)
# %%
class COUNTRY(enum.IntEnum):
DE = 1
FR = 2
CM = 3
class COUNTRY2(enum.Enum):
DE = 1
FR = 2
CM = 3
def give_value(t):
print(f"Wert ist: {t}")
give_value(COUNTRY.DE)
give_value(COUNTRY2.DE)
# %%
COUNTRY(10)
# %%
COUNTRY.DE
# %%
t_str = "asd.yxcxc.dfgjj.aasdsdsdsd.sdsdsdsd"
splitted = t_str.split(".")
part, rest = splitted[0], splitted[1:]
part
# %%
".".join([part] + rest)
# %%
class FormFieldType(enum.StrEnum): class FormFieldType(enum.StrEnum):
TEXT = enum.auto() TEXT = enum.auto()
LONGTEXT = enum.auto() LONGTEXT = enum.auto()
@@ -28,29 +108,6 @@ class FormField:
self.label += "*" self.label += "*"
# %%
DYNAMIC_LIST_KEY_PATTERN = r"-\[(\d+)\]"
key = "Schulbildung-[12].7b8da0f7-7a0e-4f71-878a-85616099e849"
matches = re.search(DYNAMIC_LIST_KEY_PATTERN, key)
# %%
matches
# %%
matches.group(1)
# %%
t_str = "asd.yxcxc.dfgjj.aasdsdsdsd.sdsdsdsd"
splitted = t_str.split(".")
part, rest = splitted[0], splitted[1:]
part
# %%
".".join([part] + rest)
# %% # %%
FormField("name", "Projektbeschreibung", FormFieldType.LONGTEXT, required=True) FormField("name", "Projektbeschreibung", FormFieldType.LONGTEXT, required=True)
# %% # %%

View File

@@ -5,7 +5,7 @@ description = "GUI for CRM of NAFKA project with WCE"
authors = [ authors = [
{name = "d-opt GmbH, resp. Florian Förster", email = "f.foerster@d-opt.com"}, {name = "d-opt GmbH, resp. Florian Förster", email = "f.foerster@d-opt.com"},
] ]
dependencies = ["nicegui>=3.10.0", "pyside6>=6.11.0", "sqlalchemy>=2.0.49", "polars>=1.40.1", "dopt-basics>=0.2.4", "pydantic>=2.13.4"] dependencies = ["nicegui>=3.10.0", "pyside6>=6.11.0", "sqlalchemy>=2.0.49", "polars>=1.40.1", "dopt-basics>=0.2.4", "pydantic>=2.13.4", "babel>=2.18.0"]
requires-python = "<3.14,>=3.11" requires-python = "<3.14,>=3.11"
readme = "README.md" readme = "README.md"
license = {text = "LicenseRef-Proprietary"} license = {text = "LicenseRef-Proprietary"}