generated from dopt-python/py311
Dev #7
+411
-98
@@ -28,7 +28,7 @@ from PySide6.QtCore import (
|
|||||||
Signal,
|
Signal,
|
||||||
qInstallMessageHandler,
|
qInstallMessageHandler,
|
||||||
)
|
)
|
||||||
from PySide6.QtGui import QAction
|
from PySide6.QtGui import QAction, QFont
|
||||||
from PySide6.QtWidgets import (
|
from PySide6.QtWidgets import (
|
||||||
QAbstractItemView,
|
QAbstractItemView,
|
||||||
QApplication,
|
QApplication,
|
||||||
@@ -77,6 +77,7 @@ from wce_crm.logging import (
|
|||||||
logger_auto_form,
|
logger_auto_form,
|
||||||
logger_get_data,
|
logger_get_data,
|
||||||
logger_gui,
|
logger_gui,
|
||||||
|
logger_page_consulting,
|
||||||
)
|
)
|
||||||
from wce_crm.types import ExtMaId, InitRecId, UserId
|
from wce_crm.types import ExtMaId, InitRecId, UserId
|
||||||
|
|
||||||
@@ -2883,29 +2884,40 @@ class MasterDataFormWidget(QWidget):
|
|||||||
|
|
||||||
@dc.dataclass(slots=True)
|
@dc.dataclass(slots=True)
|
||||||
class Session:
|
class Session:
|
||||||
user_id: UserId | None = None
|
user_id: UserId
|
||||||
user_name: str | None = None
|
user_name: str
|
||||||
|
|
||||||
|
|
||||||
@dc.dataclass(slots=True)
|
@dc.dataclass(slots=True)
|
||||||
class ConsultingSession:
|
class Page_Consulting_ConsultingSession_State:
|
||||||
user_id: UserId
|
user_id: UserId # must be set with the session (always known)
|
||||||
user_name: str
|
user_name: str # must be set with the session (always known)
|
||||||
timestamp: datetime.datetime
|
cons_session_id: int | None = None # known and not known entries
|
||||||
partner: str
|
timestamp: datetime.datetime = dc.field(
|
||||||
interaction_scheme: str
|
default_factory=lambda: datetime.datetime.now(tz=datetime.UTC)
|
||||||
topic: str # TODO should be linked to something, target unclear (need specification by customer)
|
)
|
||||||
notes: str
|
partner: str = ""
|
||||||
response: 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 = ""
|
||||||
|
|
||||||
|
|
||||||
|
@dc.dataclass(slots=True)
|
||||||
|
class Page_Consulting_Table_State:
|
||||||
|
rows: list[Page_Consulting_ConsultingSession] = dc.field(default_factory=list)
|
||||||
|
row_states: list[Page_Consulting_ConsultingSession_State] = dc.field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
@dc.dataclass(slots=True)
|
@dc.dataclass(slots=True)
|
||||||
class Page_Consulting_State:
|
class Page_Consulting_State:
|
||||||
session: Session | None = None
|
session: Session
|
||||||
un_id: InitRecId | None = None
|
un_id: InitRecId | None = None
|
||||||
pers_id: InitRecId | None = None
|
pers_id: InitRecId | None = None
|
||||||
cons_type: ConsultingType | None = None
|
cons_type: ConsultingType | None = None
|
||||||
cons_sessions: list[ConsultingSession] = dc.field(default_factory=list)
|
cons_sessions: list[Page_Consulting_ConsultingSession_State] = dc.field(
|
||||||
|
default_factory=list
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Page_Consulting(QWidget):
|
class Page_Consulting(QWidget):
|
||||||
@@ -2920,10 +2932,8 @@ class Page_Consulting(QWidget):
|
|||||||
session: Session,
|
session: Session,
|
||||||
):
|
):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.session = session
|
|
||||||
|
|
||||||
# state management
|
# state management
|
||||||
self.STATE = Page_Consulting_State()
|
self.STATE = Page_Consulting_State(session=session)
|
||||||
|
|
||||||
# self.current_id: InitRecId = -1
|
# self.current_id: InitRecId = -1
|
||||||
# self.COMPANY_FETAURES_MASTER_DATA: dict[str, str] = {
|
# self.COMPANY_FETAURES_MASTER_DATA: dict[str, str] = {
|
||||||
@@ -2951,7 +2961,7 @@ class Page_Consulting(QWidget):
|
|||||||
# --- HEADER ---
|
# --- HEADER ---
|
||||||
header_container = QWidget()
|
header_container = QWidget()
|
||||||
header_container.setMinimumWidth(700)
|
header_container.setMinimumWidth(700)
|
||||||
header_container.setMaximumWidth(1200)
|
header_container.setMaximumWidth(1500)
|
||||||
header_container.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
header_container.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
||||||
header_layout = QVBoxLayout(header_container)
|
header_layout = QVBoxLayout(header_container)
|
||||||
header_layout.setContentsMargins(0, 0, 0, 10)
|
header_layout.setContentsMargins(0, 0, 0, 10)
|
||||||
@@ -2984,7 +2994,7 @@ class Page_Consulting(QWidget):
|
|||||||
scroll_area = QScrollArea()
|
scroll_area = QScrollArea()
|
||||||
scroll_area.setWidgetResizable(True)
|
scroll_area.setWidgetResizable(True)
|
||||||
scroll_area.setMinimumWidth(700)
|
scroll_area.setMinimumWidth(700)
|
||||||
scroll_area.setMaximumWidth(1200)
|
scroll_area.setMaximumWidth(1500)
|
||||||
scroll_area.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
scroll_area.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||||
# optional: remove frame to look more modern
|
# optional: remove frame to look more modern
|
||||||
scroll_area.setFrameShape(QFrame.Shape.NoFrame)
|
scroll_area.setFrameShape(QFrame.Shape.NoFrame)
|
||||||
@@ -3009,6 +3019,9 @@ class Page_Consulting(QWidget):
|
|||||||
# layout_change_title.addWidget(change_title_btn)
|
# layout_change_title.addWidget(change_title_btn)
|
||||||
# change_title_btn.clicked.connect(self.set_company_name)
|
# change_title_btn.clicked.connect(self.set_company_name)
|
||||||
# container_layout.addLayout(layout_change_title)
|
# container_layout.addLayout(layout_change_title)
|
||||||
|
btn_get_data_table = QPushButton("Call 'get_data' from table")
|
||||||
|
btn_get_data_table.clicked.connect(self._debug_get_data_table)
|
||||||
|
container_layout.addWidget(btn_get_data_table)
|
||||||
|
|
||||||
separator2 = QFrame()
|
separator2 = QFrame()
|
||||||
separator2.setFrameShape(QFrame.Shape.HLine)
|
separator2.setFrameShape(QFrame.Shape.HLine)
|
||||||
@@ -3033,24 +3046,28 @@ class Page_Consulting(QWidget):
|
|||||||
type_layout.addWidget(self.type_pauschal_btn)
|
type_layout.addWidget(self.type_pauschal_btn)
|
||||||
type_layout.addWidget(self.type_individual_btn)
|
type_layout.addWidget(self.type_individual_btn)
|
||||||
|
|
||||||
container_layout.addSpacing(20)
|
# container_layout.addSpacing(50)
|
||||||
|
table_state = Page_Consulting_Table_State()
|
||||||
|
self.table_sessions = Page_Consulting_Table(site_state=self.STATE, state=table_state)
|
||||||
|
container_layout.addWidget(self.table_sessions)
|
||||||
|
# container_layout.addSpacing(50)
|
||||||
|
|
||||||
self.layout_sessions = QVBoxLayout()
|
# self.layout_sessions = QVBoxLayout()
|
||||||
self.layout_sessions.setContentsMargins(0, 0, 0, 0)
|
# self.layout_sessions.setContentsMargins(0, 0, 0, 0)
|
||||||
container_layout.addLayout(self.layout_sessions)
|
# container_layout.addLayout(self.layout_sessions)
|
||||||
self.btn_add_cons_session = QPushButton("+ Hinzufügen")
|
# self.btn_add_cons_session = QPushButton("+ Hinzufügen")
|
||||||
self.btn_add_cons_session.setStyleSheet(
|
# self.btn_add_cons_session.setStyleSheet(
|
||||||
"color: #0369a1; font-weight: bold; border: 1px dashed #0369a1; padding: 5px;"
|
# "color: #0369a1; font-weight: bold; border: 1px dashed #0369a1; padding: 5px;"
|
||||||
)
|
# )
|
||||||
self.btn_add_cons_session.clicked.connect(self.add_cons_entry)
|
# self.btn_add_cons_session.clicked.connect(self.add_cons_entry)
|
||||||
self.layout_sessions.addWidget(self.btn_add_cons_session)
|
# self.layout_sessions.addWidget(self.btn_add_cons_session)
|
||||||
self.layout_sessions.addStretch(1)
|
# self.layout_sessions.addStretch(1)
|
||||||
|
|
||||||
self.cons_entries: list[QWidget] = []
|
# self.cons_entries: list[QWidget] = []
|
||||||
|
|
||||||
# self.layout_sessions.addStretch()
|
# self.layout_sessions.addStretch()
|
||||||
|
|
||||||
container_layout.addStretch()
|
# container_layout.addStretch()
|
||||||
|
|
||||||
# --- STYLE ---
|
# --- STYLE ---
|
||||||
self.setStyleSheet("""
|
self.setStyleSheet("""
|
||||||
@@ -3084,45 +3101,53 @@ class Page_Consulting(QWidget):
|
|||||||
# }
|
# }
|
||||||
# """)
|
# """)
|
||||||
|
|
||||||
def add_cons_entry(self) -> None:
|
# def add_cons_entry(self) -> None:
|
||||||
logger_gui.debug("[Consulting Page] Adding entry...")
|
# logger_gui.debug("[Consulting Page] Adding entry...")
|
||||||
|
|
||||||
row_widget = QWidget()
|
# row_widget = QWidget()
|
||||||
entry_row = QHBoxLayout(row_widget)
|
# entry_row = QHBoxLayout(row_widget)
|
||||||
entry_fields = QHBoxLayout()
|
# entry_fields = QHBoxLayout()
|
||||||
entry_row.addLayout(entry_fields)
|
# entry_row.addLayout(entry_fields)
|
||||||
|
|
||||||
txt1 = QLineEdit()
|
# txt1 = QLineEdit()
|
||||||
txt2 = QPlainTextEdit()
|
# txt2 = QPlainTextEdit()
|
||||||
txt2.setMaximumHeight(100)
|
# txt2.setMaximumHeight(100)
|
||||||
entry_fields.addWidget(txt1)
|
# entry_fields.addWidget(txt1)
|
||||||
entry_fields.addWidget(txt2)
|
# entry_fields.addWidget(txt2)
|
||||||
|
|
||||||
del_btn = QPushButton("🗑️")
|
# del_btn = QPushButton("🗑️")
|
||||||
del_btn.setFixedSize(30, 30)
|
# del_btn.setFixedSize(30, 30)
|
||||||
# Lambda with default parameter to delete exactly this(!) box
|
# # Lambda with default parameter to delete exactly this(!) box
|
||||||
del_btn.clicked.connect(
|
# del_btn.clicked.connect(
|
||||||
lambda checked=False, widget=row_widget: self.remove_cons_entry(widget)
|
# lambda checked=False, widget=row_widget: self.remove_cons_entry(widget)
|
||||||
)
|
# )
|
||||||
entry_row.addWidget(del_btn)
|
# entry_row.addWidget(del_btn)
|
||||||
|
|
||||||
row_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
|
# row_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
|
||||||
# row_widget.setMaximumHeight(200)
|
# # row_widget.setMaximumHeight(200)
|
||||||
|
|
||||||
self.cons_entries.append(row_widget)
|
# self.cons_entries.append(row_widget)
|
||||||
self.layout_sessions.insertWidget(self.layout_sessions.count() - 2, row_widget)
|
# self.layout_sessions.insertWidget(self.layout_sessions.count() - 2, row_widget)
|
||||||
|
|
||||||
def remove_cons_entry(
|
# def remove_cons_entry(
|
||||||
self,
|
# self,
|
||||||
row_widget: QWidget,
|
# row_widget: QWidget,
|
||||||
) -> None:
|
# ) -> None:
|
||||||
logger_gui.debug("[Consulting Page]: Delete clicked...")
|
# logger_gui.debug("[Consulting Page]: Delete clicked...")
|
||||||
self.layout_sessions.removeWidget(row_widget)
|
# self.layout_sessions.removeWidget(row_widget)
|
||||||
row_widget.deleteLater()
|
# row_widget.deleteLater()
|
||||||
self.cons_entries.remove(row_widget)
|
# self.cons_entries.remove(row_widget)
|
||||||
|
|
||||||
|
def _debug_get_data_table(self) -> None:
|
||||||
|
self.table_sessions.get_data()
|
||||||
|
|
||||||
# TODO placeholder, check if needed
|
# TODO placeholder, check if needed
|
||||||
def _sync_state_to_ui(self) -> None: ...
|
def _sync_state_to_ui(self) -> None:
|
||||||
|
match self.STATE.cons_type:
|
||||||
|
case ConsultingType.PAUSCHAL:
|
||||||
|
self.type_pauschal_btn.setChecked(True)
|
||||||
|
case ConsultingType.INDIVIUAL:
|
||||||
|
self.type_individual_btn.setChecked(True)
|
||||||
|
|
||||||
def _sync_ui_to_state(self) -> None: ...
|
def _sync_ui_to_state(self) -> None: ...
|
||||||
|
|
||||||
@@ -3154,49 +3179,337 @@ class Page_Consulting(QWidget):
|
|||||||
self.STATE.pers_id = req.pers_id
|
self.STATE.pers_id = req.pers_id
|
||||||
self.STATE.cons_type = req.cons_type
|
self.STATE.cons_type = req.cons_type
|
||||||
|
|
||||||
# def set_company_name(self, name: str) -> None:
|
self._sync_state_to_ui()
|
||||||
# if not name:
|
|
||||||
# name = self.change_title_text.text()
|
|
||||||
# if not name:
|
|
||||||
# name = "n.v."
|
|
||||||
|
|
||||||
# txt = f"Unternehmen: {name}"
|
|
||||||
# self.title_company_name.setText(txt)
|
|
||||||
|
|
||||||
# def load_from_id(
|
class Page_Consulting_ConsultingSession(QWidget):
|
||||||
# self,
|
"""child of 'Page_Consulting_DynamicTable'"""
|
||||||
# id_: InitRecId,
|
|
||||||
# ) -> None:
|
|
||||||
# assert id_ is not None, "tried to load with InitRecId None"
|
|
||||||
# logger_gui.debug(f"Called function to load with ID: {id_}")
|
|
||||||
|
|
||||||
# if id_ < 0:
|
delete_request = Signal(QWidget)
|
||||||
# # just clear and do nothing else
|
|
||||||
# logger_gui.debug("just reset with ID < 0")
|
|
||||||
# self.table_master_data.reset()
|
|
||||||
# self.set_company_name("")
|
|
||||||
# self.current_id = id_
|
|
||||||
# return
|
|
||||||
|
|
||||||
# if id_ == self.current_id:
|
def __init__(
|
||||||
# logger_gui.debug("ID did not change. Do nothing")
|
self,
|
||||||
# self.current_id = id_
|
site_state: Page_Consulting_State,
|
||||||
# return
|
state: Page_Consulting_ConsultingSession_State,
|
||||||
|
) -> None:
|
||||||
|
super().__init__()
|
||||||
|
assert isinstance(site_state, Page_Consulting_State)
|
||||||
|
assert isinstance(state, Page_Consulting_ConsultingSession_State)
|
||||||
|
self.SITE_STATE = site_state
|
||||||
|
self.STATE = state
|
||||||
|
layout = QHBoxLayout(self)
|
||||||
|
layout.setContentsMargins(0, 2, 0, 2) # Sehr kompakt
|
||||||
|
layout.setSpacing(10)
|
||||||
|
layout.setAlignment(Qt.AlignmentFlag.AlignVCenter)
|
||||||
|
ROW_HEIGHT = 70
|
||||||
|
|
||||||
# init_rec = backend.initrec_company_get_initial_recording(id_)
|
self.user_field = QLineEdit(
|
||||||
# ma_id = cast(ExtMaId, init_rec["Partnersuche__un_suche"])
|
placeholderText="wird über aktiven Nutzer bei Anlage gesetzt"
|
||||||
# assert ma_id is not None, "no ma_id obtained"
|
)
|
||||||
# comp_info = backend.initrec_comp_search_get_info(ma_id)
|
self.timestamp = QLineEdit() # TODO change to custom date field
|
||||||
|
|
||||||
# data: dict[str, Any] = {}
|
self.contact = QLineEdit(placeholderText="Freitext")
|
||||||
|
self.contact_type = QLineEdit(placeholderText="sollte Dropdown sein") # Dropdown
|
||||||
|
self.crm_link = QLineEdit(placeholderText="CRM Links")
|
||||||
|
|
||||||
# for feature, value in comp_info.items():
|
self.plain_text = QPlainTextEdit()
|
||||||
# if feature in self.COMPANY_FETAURES_MASTER_DATA:
|
self.response = QPlainTextEdit()
|
||||||
# data[self.COMPANY_FETAURES_MASTER_DATA[feature]] = value
|
|
||||||
|
|
||||||
# self.table_master_data.load_data(data)
|
self.btn_delete = QPushButton("✕")
|
||||||
# self.set_company_name(data["Name:"])
|
self.btn_delete.setFlat(True) # Entfernt den blockigen Rahmen
|
||||||
# self.current_id = id_
|
self.btn_delete.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
widgets = (
|
||||||
|
self.user_field,
|
||||||
|
self.timestamp,
|
||||||
|
self.contact,
|
||||||
|
self.contact_type,
|
||||||
|
self.crm_link,
|
||||||
|
self.plain_text,
|
||||||
|
self.response,
|
||||||
|
self.btn_delete,
|
||||||
|
)
|
||||||
|
for widget in widgets:
|
||||||
|
widget.setFixedHeight(ROW_HEIGHT)
|
||||||
|
layout.addWidget(widget)
|
||||||
|
|
||||||
|
# column stretching: must be matched with header
|
||||||
|
num_widgets = len(widgets)
|
||||||
|
for i, widget in enumerate(widgets):
|
||||||
|
stretch: int
|
||||||
|
if i == (num_widgets - 1):
|
||||||
|
stretch = 0
|
||||||
|
else:
|
||||||
|
if "plaintext" in widget.__class__.__name__.lower():
|
||||||
|
stretch = 2
|
||||||
|
else:
|
||||||
|
stretch = 1
|
||||||
|
|
||||||
|
layout.setStretch(i, stretch)
|
||||||
|
|
||||||
|
self.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
|
||||||
|
self._sync_state_to_gui() # ?? only needed if entry is from database?
|
||||||
|
|
||||||
|
def _sync_state_to_gui(self) -> None:
|
||||||
|
# TODO set correct timestamp
|
||||||
|
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)
|
||||||
|
set_widget_value(self.contact, self.STATE.partner)
|
||||||
|
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)
|
||||||
|
|
||||||
|
def _sync_gui_to_state(self) -> None:
|
||||||
|
# TODO: get timestamp from custom field self.STATE.timestamp
|
||||||
|
self.STATE.timestamp = datetime.datetime.strptime(
|
||||||
|
self.timestamp.text(), "%d.%m.%Y %H:%M:%S"
|
||||||
|
)
|
||||||
|
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()
|
||||||
|
|
||||||
|
def get_data(self) -> Page_Consulting_ConsultingSession_State:
|
||||||
|
self._sync_gui_to_state()
|
||||||
|
|
||||||
|
return self.STATE
|
||||||
|
|
||||||
|
|
||||||
|
class Page_Consulting_Table(QWidget):
|
||||||
|
"""child of 'Page_Consulting'"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
site_state: Page_Consulting_State,
|
||||||
|
state: Page_Consulting_Table_State,
|
||||||
|
) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.setWindowTitle("Native Dynamische Liste")
|
||||||
|
self.resize(600, 400)
|
||||||
|
|
||||||
|
self.STATE = state
|
||||||
|
self.SITE_STATE = site_state
|
||||||
|
|
||||||
|
main_layout = QVBoxLayout(self)
|
||||||
|
main_layout.setContentsMargins(0, 15, 0, 15)
|
||||||
|
main_layout.setSpacing(10)
|
||||||
|
|
||||||
|
# --- BUTTON (ADD) ---
|
||||||
|
self.btn_add = QPushButton("+ Neuen Eintrag hinzufügen")
|
||||||
|
self.btn_add.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||||
|
self.btn_add.setObjectName("BlueAddButton") # ID vergeben
|
||||||
|
main_layout.addWidget(self.btn_add)
|
||||||
|
self.btn_add.clicked.connect(lambda: self.add_row(None))
|
||||||
|
|
||||||
|
self.btn_add.setStyleSheet("""
|
||||||
|
#BlueAddButton {
|
||||||
|
background-color: #007acc;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px 15px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
#BlueAddButton:hover {
|
||||||
|
background-color: #0098ff;
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
|
||||||
|
# --- HEADER ---
|
||||||
|
header_widget = QWidget()
|
||||||
|
header_layout = QHBoxLayout(header_widget)
|
||||||
|
header_layout.setContentsMargins(0, 5, 0, 5)
|
||||||
|
header_layout.setSpacing(10)
|
||||||
|
|
||||||
|
lbl_user_field = QLabel("Wer")
|
||||||
|
lbl_timestamp = QLabel("Wann")
|
||||||
|
lbl_contact = QLabel("Mit wem")
|
||||||
|
lbl_contact_type = QLabel("Wie")
|
||||||
|
lbl_crm_link = QLabel("Was")
|
||||||
|
lbl_plain_text = QLabel("Anmerkungen")
|
||||||
|
lbl_response = QLabel("Rückmeldung")
|
||||||
|
lbl_action_delete = QLabel("")
|
||||||
|
lbl_action_delete.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
lbl_action_delete.setFixedWidth(30)
|
||||||
|
|
||||||
|
labels = (
|
||||||
|
lbl_user_field,
|
||||||
|
lbl_timestamp,
|
||||||
|
lbl_contact,
|
||||||
|
lbl_contact_type,
|
||||||
|
lbl_crm_link,
|
||||||
|
lbl_plain_text,
|
||||||
|
lbl_response,
|
||||||
|
lbl_action_delete,
|
||||||
|
)
|
||||||
|
|
||||||
|
header_font = QFont()
|
||||||
|
header_font.setBold(True)
|
||||||
|
for lbl in labels:
|
||||||
|
lbl.setFont(header_font)
|
||||||
|
lbl.setStyleSheet("color: #666666;")
|
||||||
|
lbl.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
header_layout.addWidget(lbl)
|
||||||
|
|
||||||
|
plaintext_labels = {lbl_plain_text, lbl_response}
|
||||||
|
|
||||||
|
num_labels = len(labels)
|
||||||
|
for i, widget in enumerate(labels):
|
||||||
|
stretch: int
|
||||||
|
if i == (num_labels - 1):
|
||||||
|
stretch = 0
|
||||||
|
else:
|
||||||
|
if widget in plaintext_labels:
|
||||||
|
stretch = 2
|
||||||
|
else:
|
||||||
|
stretch = 1
|
||||||
|
|
||||||
|
header_layout.setStretch(i, stretch)
|
||||||
|
|
||||||
|
main_layout.addWidget(header_widget)
|
||||||
|
|
||||||
|
separator = QFrame()
|
||||||
|
separator.setFrameShape(QFrame.Shape.HLine)
|
||||||
|
separator.setFrameShadow(QFrame.Shadow.Sunken)
|
||||||
|
main_layout.addWidget(separator)
|
||||||
|
|
||||||
|
self.scroll_area = QScrollArea()
|
||||||
|
self.scroll_area.setWidgetResizable(True)
|
||||||
|
self.scroll_area.setFrameShape(QScrollArea.Shape.NoFrame)
|
||||||
|
|
||||||
|
self.container_widget = QWidget()
|
||||||
|
self.container_layout = QVBoxLayout(self.container_widget)
|
||||||
|
self.container_layout.setContentsMargins(0, 5, 0, 5)
|
||||||
|
self.container_layout.setSpacing(6)
|
||||||
|
self.container_layout.addStretch()
|
||||||
|
|
||||||
|
self.scroll_area.setWidget(self.container_widget)
|
||||||
|
main_layout.addWidget(self.scroll_area)
|
||||||
|
|
||||||
|
# --- STYLING (QSS) ---
|
||||||
|
# self.setStyleSheet("""
|
||||||
|
# QWidget {
|
||||||
|
# background-color: #1e1e24;
|
||||||
|
# color: #e0e0e6;
|
||||||
|
# font-family: 'Segoe UI', sans-serif;
|
||||||
|
# font-size: 13px;
|
||||||
|
# }
|
||||||
|
# #HeaderWidget QLabel {
|
||||||
|
# font-weight: bold;
|
||||||
|
# color: #888892;
|
||||||
|
# font-size: 11px;
|
||||||
|
# letter-spacing: 1px;
|
||||||
|
# }
|
||||||
|
# QLineEdit {
|
||||||
|
# background-color: #2a2a32;
|
||||||
|
# border: 1px solid #3f3f4a;
|
||||||
|
# border-radius: 6px;
|
||||||
|
# padding: 6px 10px;
|
||||||
|
# color: white;
|
||||||
|
# }
|
||||||
|
# QLineEdit:focus {
|
||||||
|
# border: 1px solid #007acc;
|
||||||
|
# }
|
||||||
|
# QPushButton {
|
||||||
|
# background-color: #007acc;
|
||||||
|
# color: white;
|
||||||
|
# border: none;
|
||||||
|
# border-radius: 6px;
|
||||||
|
# padding: 8px 15px;
|
||||||
|
# font-weight: bold;
|
||||||
|
# }
|
||||||
|
# QPushButton:hover {
|
||||||
|
# background-color: #0098ff;
|
||||||
|
# }
|
||||||
|
# #DeleteButton {
|
||||||
|
# background-color: transparent;
|
||||||
|
# color: #ff5555;
|
||||||
|
# border: 1px solid #3f3f4a;
|
||||||
|
# font-size: 14px;
|
||||||
|
# padding: 4px;
|
||||||
|
# }
|
||||||
|
# #DeleteButton:hover {
|
||||||
|
# background-color: #ff3333;
|
||||||
|
# color: white;
|
||||||
|
# border-color: #ff3333;
|
||||||
|
# }
|
||||||
|
# QScrollArea {
|
||||||
|
# background-color: transparent;
|
||||||
|
# }
|
||||||
|
# """)
|
||||||
|
|
||||||
|
if DEBUG:
|
||||||
|
# add rows for debugging
|
||||||
|
self.add_row()
|
||||||
|
self.add_row()
|
||||||
|
|
||||||
|
def add_row(
|
||||||
|
self,
|
||||||
|
row_state: Page_Consulting_ConsultingSession_State | None = None,
|
||||||
|
) -> 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,
|
||||||
|
)
|
||||||
|
|
||||||
|
row = Page_Consulting_ConsultingSession(site_state=self.SITE_STATE, state=row_state)
|
||||||
|
row.delete_request.connect(self.remove_row)
|
||||||
|
|
||||||
|
index = self.container_layout.count() - 1
|
||||||
|
self.container_layout.insertWidget(index, row)
|
||||||
|
self.STATE.rows.append(row)
|
||||||
|
|
||||||
|
def remove_row(
|
||||||
|
self,
|
||||||
|
table_row_widget: Page_Consulting_ConsultingSession,
|
||||||
|
) -> None:
|
||||||
|
self.container_layout.removeWidget(table_row_widget)
|
||||||
|
self.STATE.rows.remove(table_row_widget)
|
||||||
|
table_row_widget.deleteLater()
|
||||||
|
|
||||||
|
def reset(self) -> None:
|
||||||
|
while self.STATE.rows:
|
||||||
|
self.remove_row(self.STATE.rows[0])
|
||||||
|
|
||||||
|
def _sync_state_to_gui(self) -> None:
|
||||||
|
for row_state in self.STATE.row_states:
|
||||||
|
self.add_row(row_state)
|
||||||
|
|
||||||
|
def _sync_gui_to_state(self) -> None:
|
||||||
|
row_data: list[Page_Consulting_ConsultingSession_State] = []
|
||||||
|
|
||||||
|
for i in range(self.container_layout.count() - 1):
|
||||||
|
item = self.container_layout.itemAt(i)
|
||||||
|
assert item, "item not found"
|
||||||
|
widget = item.widget()
|
||||||
|
assert widget, "no widget obtained"
|
||||||
|
|
||||||
|
if isinstance(widget, Page_Consulting_ConsultingSession):
|
||||||
|
row_data.append(widget.get_data())
|
||||||
|
|
||||||
|
assert len(row_data) == len(self.STATE.rows), "mismatch in row count and data length"
|
||||||
|
self.STATE.row_states = row_data
|
||||||
|
|
||||||
|
def get_data(self) -> Page_Consulting_Table_State:
|
||||||
|
logger_page_consulting.debug("[Page Consulting -- Table] Syncing GUI to state...")
|
||||||
|
self._sync_gui_to_state()
|
||||||
|
|
||||||
|
logger_page_consulting.debug("[Page Consulting -- Table]: State = %s", self.STATE)
|
||||||
|
|
||||||
|
return self.STATE
|
||||||
|
|
||||||
|
|
||||||
|
####################################################################
|
||||||
|
|
||||||
|
|
||||||
def clear_layout(
|
def clear_layout(
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ logger_get_data.setLevel(logging.DEBUG)
|
|||||||
logger_auto_form = logger_gui.getChild("get_data_auto_form")
|
logger_auto_form = logger_gui.getChild("get_data_auto_form")
|
||||||
logger_auto_form.setLevel(logging.DEBUG)
|
logger_auto_form.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
logger_page_consulting = logger_gui.getChild("page_consulting")
|
||||||
|
logger_page_consulting.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
# ** Backend
|
# ** Backend
|
||||||
logger_back = logger_base.getChild("backend")
|
logger_back = logger_base.getChild("backend")
|
||||||
logger_back.setLevel(logging.DEBUG)
|
logger_back.setLevel(logging.DEBUG)
|
||||||
|
|||||||
Reference in New Issue
Block a user