generated from dopt-python/py311
generic typing of field definitions and value getter function for single widgets
This commit is contained in:
@@ -4,12 +4,17 @@ import dataclasses as dc
|
||||
import enum
|
||||
import uuid
|
||||
from collections.abc import Sequence
|
||||
from typing import Any, Final
|
||||
from typing import TYPE_CHECKING, Any, Final, Generic, TypeVar
|
||||
|
||||
import babel
|
||||
|
||||
from wce_crm.custom_widget_registry import CUSTOM_WIDGET_NAMES
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from PySide6.QtWidgets import QWidget
|
||||
|
||||
T = TypeVar("T", bound="QWidget")
|
||||
|
||||
|
||||
class FormFieldType(enum.StrEnum):
|
||||
GROUP = enum.auto()
|
||||
@@ -31,7 +36,7 @@ class FormFieldType(enum.StrEnum):
|
||||
|
||||
|
||||
@dc.dataclass(slots=True)
|
||||
class FormField:
|
||||
class FormField(Generic[T]):
|
||||
label: str
|
||||
type: FormFieldType
|
||||
children: Sequence[FormField] = dc.field(default_factory=list)
|
||||
|
||||
+142
-75
@@ -12,7 +12,17 @@ from collections import defaultdict
|
||||
from collections.abc import Container, Iterable, Sequence
|
||||
from pathlib import Path
|
||||
from pprint import pformat
|
||||
from typing import TYPE_CHECKING, Any, Final, Protocol, TypeAlias, TypedDict, TypeVar, cast
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Final,
|
||||
Literal,
|
||||
Protocol,
|
||||
TypeAlias,
|
||||
TypedDict,
|
||||
TypeVar,
|
||||
cast,
|
||||
)
|
||||
from typing_extensions import override
|
||||
|
||||
from dopt_basics import datetime as dopt_dt
|
||||
@@ -92,6 +102,7 @@ if TYPE_CHECKING:
|
||||
|
||||
K = TypeVar("K")
|
||||
V = TypeVar("V")
|
||||
T = TypeVar("T", bound="QWidget")
|
||||
|
||||
|
||||
DEBUG: bool = True
|
||||
@@ -274,7 +285,7 @@ class CustomWidget(QWidget):
|
||||
|
||||
|
||||
def _add_widget_to_layout(
|
||||
form_field: FormField,
|
||||
form_field: FormField[T],
|
||||
widget: QWidget,
|
||||
target_layout: QLayout,
|
||||
widget_only: bool = False,
|
||||
@@ -299,10 +310,10 @@ def _add_widget_to_layout(
|
||||
|
||||
|
||||
def build_and_add_widget(
|
||||
form_field: FormField,
|
||||
form_field: FormField[T],
|
||||
parent_layout: QLayout,
|
||||
prefix: str = "",
|
||||
) -> tuple[str, QWidget]:
|
||||
) -> tuple[str, T]:
|
||||
no_scroll_filter = NoScrollFilter(parent_layout)
|
||||
if prefix and form_field.key:
|
||||
full_key = f"{prefix}{COLUMN_SEP}{form_field.key}" if prefix else form_field.key
|
||||
@@ -311,7 +322,6 @@ def build_and_add_widget(
|
||||
else:
|
||||
full_key = form_field.key
|
||||
|
||||
widget: QWidget
|
||||
layout_widget_only: bool = False
|
||||
install_no_scroll_filter: bool = True
|
||||
|
||||
@@ -496,7 +506,7 @@ def build_and_add_widget(
|
||||
|
||||
_add_widget_to_layout(form_field, widget, parent_layout, widget_only=layout_widget_only)
|
||||
|
||||
return full_key, widget
|
||||
return full_key, cast(T, widget)
|
||||
|
||||
|
||||
def _build_ui_recursively(
|
||||
@@ -711,40 +721,35 @@ def get_form_data(
|
||||
ignored_keys.append(key)
|
||||
continue
|
||||
|
||||
if isinstance(widget, QLineEdit):
|
||||
data = widget.text()
|
||||
if data != "":
|
||||
value = data
|
||||
if form_field.type is FormFieldType.TEXT_DATE:
|
||||
value = datetime.datetime.strptime(value, DATE_FMT).date()
|
||||
elif form_field.type is FormFieldType.TEXT_DATETIME:
|
||||
value = datetime.datetime.strptime(value, DATETIME_FMT)
|
||||
elif isinstance(widget, QPlainTextEdit):
|
||||
data = widget.toPlainText()
|
||||
if data != "":
|
||||
value = data
|
||||
elif isinstance(widget, QDateEdit):
|
||||
qt_date = widget.date()
|
||||
value = qt_date.toPython()
|
||||
elif isinstance(widget, FlexibleDateInput):
|
||||
value = widget.get_pydate()
|
||||
elif isinstance(widget, FlexibleDateTimeInput):
|
||||
value = widget.get_pydatetime()
|
||||
elif isinstance(widget, QComboBox):
|
||||
value = widget.currentData()
|
||||
elif isinstance(
|
||||
widget,
|
||||
(
|
||||
DynamicListWidget,
|
||||
DynamicDropdownWidgetNumeric,
|
||||
DynamicDropdownWidgetOption,
|
||||
CustomWidget,
|
||||
),
|
||||
):
|
||||
# this is a special data structure with some assumptions of the widget's internals
|
||||
# DynamicListWidget: this is a list -> each dynamic list contains a list
|
||||
# of such dictionaries (handled below)
|
||||
value = widget.get_form_data()
|
||||
if form_field.type is FormFieldType.TEXT_DATE:
|
||||
value = get_widget_value(widget, "date")
|
||||
elif form_field.type is FormFieldType.TEXT_DATETIME:
|
||||
value = get_widget_value(widget, "datetime")
|
||||
else:
|
||||
value = get_widget_value(widget)
|
||||
|
||||
# elif isinstance(widget, QDateEdit):
|
||||
# qt_date = widget.date()
|
||||
# value = qt_date.toPython()
|
||||
# elif isinstance(widget, FlexibleDateInput):
|
||||
# value = widget.get_pydate()
|
||||
# elif isinstance(widget, FlexibleDateTimeInput):
|
||||
# value = widget.get_pydatetime()
|
||||
# elif isinstance(widget, QComboBox):
|
||||
# value = widget.currentData()
|
||||
# elif isinstance(
|
||||
# widget,
|
||||
# (
|
||||
# DynamicListWidget,
|
||||
# DynamicDropdownWidgetNumeric,
|
||||
# DynamicDropdownWidgetOption,
|
||||
# CustomWidget,
|
||||
# ),
|
||||
# ):
|
||||
# # this is a special data structure with some assumptions of the widget's internals
|
||||
# # DynamicListWidget: this is a list -> each dynamic list contains a list
|
||||
# # of such dictionaries (handled below)
|
||||
# value = widget.get_form_data()
|
||||
|
||||
if isinstance(value, dict):
|
||||
raw_data.update(value)
|
||||
@@ -756,6 +761,50 @@ def get_form_data(
|
||||
return raw_data
|
||||
|
||||
|
||||
def get_widget_value(
|
||||
widget: QWidget,
|
||||
text_type: Literal["default", "date", "datetime"] = "default",
|
||||
) -> Any:
|
||||
value: Any | None = None
|
||||
|
||||
if isinstance(widget, QLineEdit):
|
||||
data = widget.text()
|
||||
if data != "":
|
||||
value = data
|
||||
if text_type == "date":
|
||||
value = datetime.datetime.strptime(value, DATE_FMT).date()
|
||||
elif text_type == "datetime":
|
||||
value = datetime.datetime.strptime(value, DATETIME_FMT)
|
||||
elif isinstance(widget, QPlainTextEdit):
|
||||
data = widget.toPlainText()
|
||||
if data != "":
|
||||
value = data
|
||||
elif isinstance(widget, QDateEdit):
|
||||
qt_date = widget.date()
|
||||
value = qt_date.toPython()
|
||||
elif isinstance(widget, FlexibleDateInput):
|
||||
value = widget.get_pydate()
|
||||
elif isinstance(widget, FlexibleDateTimeInput):
|
||||
value = widget.get_pydatetime()
|
||||
elif isinstance(widget, QComboBox):
|
||||
value = widget.currentData()
|
||||
elif isinstance(
|
||||
widget,
|
||||
(
|
||||
DynamicListWidget,
|
||||
DynamicDropdownWidgetNumeric,
|
||||
DynamicDropdownWidgetOption,
|
||||
CustomWidget,
|
||||
),
|
||||
):
|
||||
# this is a special data structure with some assumptions of the widget's internals
|
||||
# DynamicListWidget: this is a list -> each dynamic list contains a list
|
||||
# of such dictionaries (handled below)
|
||||
value = widget.get_form_data()
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def set_widget_value(
|
||||
widget: QWidget,
|
||||
value: Any,
|
||||
@@ -3301,17 +3350,19 @@ class Session:
|
||||
|
||||
@dc.dataclass(slots=True)
|
||||
class Page_Consulting_ConsultingSession_State:
|
||||
user_id: UserId # must be set with the session (always known)
|
||||
user_name: str # must be set with the session (always known)
|
||||
cons_session_id: int | None = None # known and not known entries
|
||||
timestamp: datetime.datetime = dc.field(
|
||||
nutzer_id: UserId # must be set with the session (always known)
|
||||
nutzer_name: str # must be set with the session (always known)
|
||||
beratung_id: int | None = None # known and not known entries
|
||||
zeitstempel: datetime.datetime = dc.field(
|
||||
default_factory=lambda: datetime.datetime.now(tz=datetime.UTC)
|
||||
)
|
||||
partner: str = ""
|
||||
interaction_scheme: str = "" # set string like in other dropdowns or use integer (enum)
|
||||
topic: str = "" # TODO should be linked to something, target unclear (need specification by customer)
|
||||
notes: str = ""
|
||||
response: str = ""
|
||||
ansprechpartner: str | None = None
|
||||
interaction_scheme: str | None = None
|
||||
topic: str | None = (
|
||||
None # TODO should be linked to something, target unclear (need specification by customer)
|
||||
)
|
||||
anmerkungen: str | None = None
|
||||
rueckmeldung: str | None = None
|
||||
|
||||
|
||||
@dc.dataclass(slots=True)
|
||||
@@ -3614,23 +3665,38 @@ class Page_Consulting_ConsultingSession(QWidget):
|
||||
layout.setAlignment(Qt.AlignmentFlag.AlignVCenter)
|
||||
ROW_HEIGHT = 70
|
||||
|
||||
self.user_field = QLineEdit(
|
||||
placeholderText="wird über aktiven Nutzer bei Anlage gesetzt"
|
||||
user_field_def = FormField[QLineEdit](
|
||||
"",
|
||||
FormFieldType.TEXT,
|
||||
readonly=True,
|
||||
placeholder="wird über aktiven Nutzer bei Anlage gesetzt",
|
||||
)
|
||||
self.user_field.setReadOnly(True)
|
||||
self.user_field.setProperty("styleClass", "stempel")
|
||||
_, self.user_field = build_and_add_widget(user_field_def, layout)
|
||||
|
||||
# ?? date or datetime?
|
||||
# self.timestamp = FlexibleDateInput()
|
||||
# self.timestamp.set_pydate(datetime.datetime.now())
|
||||
self.timestamp = FlexibleDateTimeInput()
|
||||
timestamp_def = FormField[FlexibleDateTimeInput]("", FormFieldType.DATETIME_FLEXIBLE)
|
||||
_, self.timestamp = build_and_add_widget(timestamp_def, layout)
|
||||
self.timestamp.set_pydatetime(datetime.datetime.now())
|
||||
|
||||
self.contact = QLineEdit(placeholderText="Freitext")
|
||||
self.contact_type = QLineEdit(placeholderText="sollte Dropdown sein") # Dropdown
|
||||
self.crm_link = QLineEdit(placeholderText="CRM Links")
|
||||
contact_def = FormField[QLineEdit]("", FormFieldType.TEXT, placeholder="Freitext")
|
||||
_, self.contact = build_and_add_widget(contact_def, layout)
|
||||
|
||||
self.plain_text = QPlainTextEdit()
|
||||
self.response = QPlainTextEdit()
|
||||
contact_type_def = FormField[QComboBox](
|
||||
"",
|
||||
FormFieldType.DROPDOWN,
|
||||
placeholder="sollte Dropdown sein",
|
||||
options=[("Persönlich", None), ("Telefon", None), ("Mail", None)],
|
||||
)
|
||||
_, self.contact_type = build_and_add_widget(contact_type_def, layout)
|
||||
|
||||
crm_link_def = FormField[QLineEdit]("", FormFieldType.TEXT, placeholder="CRM Links")
|
||||
_, self.crm_link = build_and_add_widget(crm_link_def, layout)
|
||||
|
||||
plain_text_def = FormField[QPlainTextEdit]("", FormFieldType.LONGTEXT)
|
||||
_, self.plain_text = build_and_add_widget(plain_text_def, layout)
|
||||
|
||||
response_def = FormField[QPlainTextEdit]("", FormFieldType.LONGTEXT)
|
||||
_, self.response = build_and_add_widget(response_def, layout)
|
||||
|
||||
self.btn_delete = QPushButton("✕")
|
||||
self.btn_delete.setFlat(True) # Entfernt den blockigen Rahmen
|
||||
@@ -3639,6 +3705,7 @@ class Page_Consulting_ConsultingSession(QWidget):
|
||||
self.btn_delete.setStyleSheet("color: #cc0000; font-weight: bold;")
|
||||
self.btn_delete.clicked.connect(lambda: self.delete_request.emit(self))
|
||||
self.btn_delete.setFixedWidth(30)
|
||||
layout.addWidget(self.btn_delete)
|
||||
|
||||
widgets = (
|
||||
self.user_field,
|
||||
@@ -3652,7 +3719,7 @@ class Page_Consulting_ConsultingSession(QWidget):
|
||||
)
|
||||
for widget in widgets:
|
||||
widget.setFixedHeight(ROW_HEIGHT)
|
||||
layout.addWidget(widget)
|
||||
# layout.addWidget(widget)
|
||||
|
||||
# column stretching: must be matched with header
|
||||
num_widgets = len(widgets)
|
||||
@@ -3676,22 +3743,22 @@ class Page_Consulting_ConsultingSession(QWidget):
|
||||
logger_page_consulting.debug(
|
||||
"[Page Consulting -- Consulting Session]: State = %s", self.STATE
|
||||
)
|
||||
set_widget_value(self.user_field, self.STATE.user_name)
|
||||
set_widget_value(self.timestamp, self.STATE.timestamp.astimezone(TIMEZONE_CEST))
|
||||
set_widget_value(self.contact, self.STATE.partner)
|
||||
set_widget_value(self.user_field, self.STATE.nutzer_name)
|
||||
set_widget_value(self.timestamp, self.STATE.zeitstempel.astimezone(TIMEZONE_CEST))
|
||||
set_widget_value(self.contact, self.STATE.ansprechpartner)
|
||||
set_widget_value(self.contact_type, self.STATE.interaction_scheme)
|
||||
set_widget_value(self.crm_link, self.STATE.topic)
|
||||
set_widget_value(self.plain_text, self.STATE.notes)
|
||||
set_widget_value(self.response, self.STATE.response)
|
||||
set_widget_value(self.plain_text, self.STATE.anmerkungen)
|
||||
set_widget_value(self.response, self.STATE.rueckmeldung)
|
||||
|
||||
def _sync_gui_to_state(self) -> None:
|
||||
# TODO: get timestamp from custom field self.STATE.timestamp
|
||||
self.STATE.timestamp = self.timestamp.get_pydatetime()
|
||||
self.STATE.partner = self.contact.text()
|
||||
self.STATE.interaction_scheme = self.contact_type.text()
|
||||
self.STATE.topic = self.crm_link.text() # TODO: change to correct link
|
||||
self.STATE.notes = self.plain_text.toPlainText()
|
||||
self.STATE.response = self.response.toPlainText()
|
||||
self.STATE.zeitstempel = self.timestamp.get_pydatetime()
|
||||
self.STATE.ansprechpartner = get_widget_value(self.contact)
|
||||
self.STATE.interaction_scheme = get_widget_value(self.contact_type)
|
||||
self.STATE.topic = get_widget_value(self.crm_link) # TODO: change to correct link
|
||||
self.STATE.anmerkungen = get_widget_value(self.plain_text)
|
||||
self.STATE.rueckmeldung = get_widget_value(self.response)
|
||||
|
||||
def get_data(self) -> Page_Consulting_ConsultingSession_State:
|
||||
self._sync_gui_to_state()
|
||||
@@ -3873,8 +3940,8 @@ class Page_Consulting_Table(QWidget):
|
||||
) -> None:
|
||||
if row_state is None:
|
||||
row_state = Page_Consulting_ConsultingSession_State(
|
||||
user_id=self.SITE_STATE.session.user_id,
|
||||
user_name=self.SITE_STATE.session.user_name,
|
||||
nutzer_id=self.SITE_STATE.session.user_id,
|
||||
nutzer_name=self.SITE_STATE.session.user_name,
|
||||
)
|
||||
|
||||
row = Page_Consulting_ConsultingSession(site_state=self.SITE_STATE, state=row_state)
|
||||
|
||||
Reference in New Issue
Block a user