719 lines
29 KiB
Python
719 lines
29 KiB
Python
import json
|
||
from datetime import date
|
||
|
||
from qgis.PyQt.QtWidgets import (
|
||
QDialog, QVBoxLayout, QHBoxLayout, QFormLayout,
|
||
QLabel, QLineEdit, QPushButton, QMessageBox, QComboBox,
|
||
QDateEdit, QSpinBox, QCheckBox, QScrollArea, QWidget,
|
||
QListWidget, QListWidgetItem, QInputDialog, QSizePolicy,
|
||
QFrame, QGroupBox
|
||
)
|
||
from qgis.PyQt.QtCore import Qt, QDate
|
||
from qgis.PyQt.QtGui import QFont, QColor
|
||
from qgis.core import QgsCoordinateReferenceSystem, QgsCoordinateTransform, QgsProject
|
||
from qgis.utils import iface
|
||
|
||
from .map_point_tool import PointCaptureTool
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Widgets utilitaires
|
||
# ---------------------------------------------------------------------------
|
||
|
||
class ComboWithAdd(QWidget):
|
||
def __init__(self, add_callback, parent=None):
|
||
super().__init__(parent)
|
||
self._add_callback = add_callback
|
||
layout = QHBoxLayout(self)
|
||
layout.setContentsMargins(0, 0, 0, 0)
|
||
self.combo = QComboBox()
|
||
self.combo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||
self.btn_add = QPushButton("+")
|
||
self.btn_add.setFixedWidth(30)
|
||
self.btn_add.setToolTip("Ajouter un nouvel élément")
|
||
self.btn_add.clicked.connect(lambda: self._add_callback(self))
|
||
layout.addWidget(self.combo)
|
||
layout.addWidget(self.btn_add)
|
||
|
||
def current_data(self):
|
||
return self.combo.currentData()
|
||
|
||
def current_text(self):
|
||
return self.combo.currentText()
|
||
|
||
def populate(self, items, placeholder=None):
|
||
self.combo.clear()
|
||
if placeholder:
|
||
self.combo.addItem(placeholder, None)
|
||
for code, label in items:
|
||
self.combo.addItem(label, code)
|
||
|
||
def add_item(self, code, label):
|
||
self.combo.addItem(label, code)
|
||
self.combo.setCurrentIndex(self.combo.count() - 1)
|
||
|
||
def set_by_text(self, text):
|
||
idx = self.combo.findText(text)
|
||
if idx >= 0:
|
||
self.combo.setCurrentIndex(idx)
|
||
|
||
def set_by_data(self, data):
|
||
idx = self.combo.findData(data)
|
||
if idx >= 0:
|
||
self.combo.setCurrentIndex(idx)
|
||
|
||
|
||
class AnimateursWidget(QWidget):
|
||
def __init__(self, db, parent=None):
|
||
super().__init__(parent)
|
||
self.db = db
|
||
layout = QVBoxLayout(self)
|
||
layout.setContentsMargins(0, 0, 0, 0)
|
||
|
||
self.list_widget = QListWidget()
|
||
self.list_widget.setMaximumHeight(90)
|
||
layout.addWidget(self.list_widget)
|
||
|
||
btn_layout = QHBoxLayout()
|
||
self.combo = QComboBox()
|
||
self.combo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||
btn_add = QPushButton("Ajouter")
|
||
btn_add.clicked.connect(self._add_existing)
|
||
btn_new = QPushButton("+ Nouveau")
|
||
btn_new.clicked.connect(self._add_new)
|
||
btn_remove = QPushButton("Retirer")
|
||
btn_remove.clicked.connect(self._remove_selected)
|
||
btn_layout.addWidget(self.combo)
|
||
btn_layout.addWidget(btn_add)
|
||
btn_layout.addWidget(btn_new)
|
||
btn_layout.addWidget(btn_remove)
|
||
layout.addLayout(btn_layout)
|
||
|
||
self.load_animateurs()
|
||
|
||
def load_animateurs(self):
|
||
self.combo.clear()
|
||
for code, nom in self.db.get_animateurs():
|
||
self.combo.addItem(nom, code)
|
||
|
||
def _add_existing(self):
|
||
code = self.combo.currentData()
|
||
nom = self.combo.currentText()
|
||
if code is None:
|
||
return
|
||
for i in range(self.list_widget.count()):
|
||
if self.list_widget.item(i).data(Qt.UserRole) == code:
|
||
return
|
||
item = QListWidgetItem(nom)
|
||
item.setData(Qt.UserRole, code)
|
||
self.list_widget.addItem(item)
|
||
|
||
def _add_new(self):
|
||
nom, ok = QInputDialog.getText(self, "Nouvel animateur", "Nom :")
|
||
if ok and nom.strip():
|
||
try:
|
||
code, label = self.db.add_animateur(nom.strip())
|
||
self.combo.addItem(label, code)
|
||
item = QListWidgetItem(label)
|
||
item.setData(Qt.UserRole, code)
|
||
self.list_widget.addItem(item)
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "Erreur", str(e))
|
||
|
||
def _remove_selected(self):
|
||
for item in self.list_widget.selectedItems():
|
||
self.list_widget.takeItem(self.list_widget.row(item))
|
||
|
||
def get_value(self):
|
||
result = []
|
||
for i in range(self.list_widget.count()):
|
||
item = self.list_widget.item(i)
|
||
result.append({"code": item.data(Qt.UserRole), "nom": item.text()})
|
||
return json.dumps(result, ensure_ascii=False) if result else None
|
||
|
||
def set_value(self, json_str):
|
||
self.list_widget.clear()
|
||
if not json_str:
|
||
return
|
||
try:
|
||
data = json.loads(json_str) if isinstance(json_str, str) else json_str
|
||
for entry in data:
|
||
item = QListWidgetItem(entry.get("nom", ""))
|
||
item.setData(Qt.UserRole, entry.get("code"))
|
||
self.list_widget.addItem(item)
|
||
except Exception:
|
||
pass
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Dialogue principal
|
||
# ---------------------------------------------------------------------------
|
||
|
||
class SaisieDialog(QDialog):
|
||
def __init__(self, db, parent=None):
|
||
super().__init__(parent)
|
||
self.db = db
|
||
self._etab_map = {} # code -> (nom, commune)
|
||
self._edit_mode = False # True = on édite une animation existante
|
||
self._edit_code = None # code_animation en cours d'édition
|
||
self._pending_geom = None # (x, y, crs) en attente pour ajout lieu/etab
|
||
self._pending_geom_type = None # 'lieu' ou 'etab'
|
||
self._point_tool = None
|
||
|
||
self.setWindowTitle("Animation – Saisie / Édition")
|
||
self.setMinimumWidth(720)
|
||
self.setMinimumHeight(820)
|
||
self._build_ui()
|
||
self._load_reference_data()
|
||
|
||
# -----------------------------------------------------------------------
|
||
# Construction UI
|
||
# -----------------------------------------------------------------------
|
||
|
||
def _build_ui(self):
|
||
main_layout = QVBoxLayout(self)
|
||
main_layout.setSpacing(6)
|
||
|
||
# --- Bandeau titre ---
|
||
self.title_label = QLabel("<h2>Nouvelle animation</h2>")
|
||
self.title_label.setAlignment(Qt.AlignCenter)
|
||
main_layout.addWidget(self.title_label)
|
||
|
||
# --- Sélecteur d'animation existante ---
|
||
grp_sel = QGroupBox("Charger / modifier une animation existante")
|
||
sel_layout = QHBoxLayout(grp_sel)
|
||
self.anim_combo = QComboBox()
|
||
self.anim_combo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||
self.anim_combo.setPlaceholderText("── Nouvelle saisie ──")
|
||
self.anim_combo.addItem("── Nouvelle saisie ──", None)
|
||
self.anim_combo.currentIndexChanged.connect(self._on_anim_selected)
|
||
sel_layout.addWidget(QLabel("Animation :"))
|
||
sel_layout.addWidget(self.anim_combo)
|
||
btn_refresh = QPushButton("🔄")
|
||
btn_refresh.setFixedWidth(32)
|
||
btn_refresh.setToolTip("Rafraîchir la liste")
|
||
btn_refresh.clicked.connect(self._reload_animations_list)
|
||
sel_layout.addWidget(btn_refresh)
|
||
main_layout.addWidget(grp_sel)
|
||
|
||
# --- Zone scrollable du formulaire ---
|
||
scroll = QScrollArea()
|
||
scroll.setWidgetResizable(True)
|
||
container = QWidget()
|
||
self.fl = QFormLayout(container)
|
||
self.fl.setLabelAlignment(Qt.AlignRight)
|
||
self.fl.setSpacing(8)
|
||
scroll.setWidget(container)
|
||
main_layout.addWidget(scroll)
|
||
|
||
fl = self.fl
|
||
|
||
# ---- Date & Durée ----
|
||
self._section(fl, "Date et durée")
|
||
|
||
self.date_edit = QDateEdit(QDate.currentDate())
|
||
self.date_edit.setCalendarPopup(True)
|
||
self.date_edit.setDisplayFormat("dd/MM/yyyy")
|
||
fl.addRow("Date *:", self.date_edit)
|
||
|
||
dur_w = QWidget()
|
||
dur_l = QHBoxLayout(dur_w)
|
||
dur_l.setContentsMargins(0, 0, 0, 0)
|
||
self.duree_h = QSpinBox()
|
||
self.duree_h.setRange(0, 24)
|
||
self.duree_h.setSuffix(" h")
|
||
self.duree_min = QSpinBox()
|
||
self.duree_min.setRange(0, 59)
|
||
self.duree_min.setSuffix(" min")
|
||
dur_l.addWidget(self.duree_h)
|
||
dur_l.addWidget(self.duree_min)
|
||
dur_l.addStretch()
|
||
fl.addRow("Durée :", dur_w)
|
||
|
||
self.prepa_spin = QSpinBox()
|
||
self.prepa_spin.setRange(0, 9999)
|
||
self.prepa_spin.setSuffix(" min")
|
||
for w in (self.duree_h, self.duree_min, self.prepa_spin):
|
||
w.valueChanged.connect(self._update_temps_total)
|
||
fl.addRow("Prépa / déplacement :", self.prepa_spin)
|
||
|
||
self.temps_total_label = QLabel("0 min")
|
||
fl.addRow("Temps total (calculé) :", self.temps_total_label)
|
||
|
||
# ---- Animateurs ----
|
||
self._sep(fl)
|
||
self._section(fl, "Animateurs")
|
||
self.animateurs_widget = AnimateursWidget(self.db)
|
||
fl.addRow("Animateurs :", self.animateurs_widget)
|
||
|
||
# ---- Groupe ----
|
||
self._sep(fl)
|
||
self._section(fl, "Groupe")
|
||
self.type_groupe_combo = ComboWithAdd(self._add_type_groupe)
|
||
fl.addRow("Type de groupe :", self.type_groupe_combo)
|
||
self.precisions_groupe_edit = QLineEdit()
|
||
fl.addRow("Précisions groupe :", self.precisions_groupe_edit)
|
||
|
||
# ---- Établissement ----
|
||
self._sep(fl)
|
||
self._section(fl, "Établissement / Provenance")
|
||
self.etab_combo = ComboWithAdd(self._add_etablissement)
|
||
self.etab_combo.combo.currentIndexChanged.connect(self._on_etab_changed)
|
||
fl.addRow("Établissement :", self.etab_combo)
|
||
self.commune_label = QLabel("")
|
||
self.commune_label.setStyleSheet("color:#555; font-style:italic;")
|
||
fl.addRow("Commune (auto) :", self.commune_label)
|
||
|
||
# ---- Participants ----
|
||
self._sep(fl)
|
||
self._section(fl, "Participants")
|
||
self.enfants_spin = QSpinBox()
|
||
self.enfants_spin.setRange(0, 9999)
|
||
self.enfants_spin.valueChanged.connect(self._update_total_pers)
|
||
fl.addRow("Enfants :", self.enfants_spin)
|
||
self.adultes_spin = QSpinBox()
|
||
self.adultes_spin.setRange(0, 9999)
|
||
self.adultes_spin.valueChanged.connect(self._update_total_pers)
|
||
fl.addRow("Adultes :", self.adultes_spin)
|
||
self.total_pers_label = QLabel("0")
|
||
fl.addRow("Total (calculé) :", self.total_pers_label)
|
||
|
||
# ---- Lieu ----
|
||
self._sep(fl)
|
||
self._section(fl, "Lieu")
|
||
self.lieux_combo = ComboWithAdd(self._add_lieu)
|
||
fl.addRow("Lieu :", self.lieux_combo)
|
||
self.precisions_lieux_edit = QLineEdit()
|
||
fl.addRow("Précisions lieu :", self.precisions_lieux_edit)
|
||
self.accueil_pin_check = QCheckBox("Oui")
|
||
fl.addRow("Accueil PIN :", self.accueil_pin_check)
|
||
|
||
# ---- Thème ----
|
||
self._sep(fl)
|
||
self._section(fl, "Thème")
|
||
self.theme_combo = ComboWithAdd(self._add_theme)
|
||
fl.addRow("Thème :", self.theme_combo)
|
||
self.theme_detaille_edit = QLineEdit()
|
||
fl.addRow("Thème détaillé :", self.theme_detaille_edit)
|
||
|
||
# ---- Statuts ----
|
||
self._sep(fl)
|
||
self._section(fl, "Statuts")
|
||
self.payant_check = QCheckBox("Oui")
|
||
fl.addRow("Payant :", self.payant_check)
|
||
self.annul_combo = ComboWithAdd(self._add_annulation)
|
||
fl.addRow("Annulation :", self.annul_combo)
|
||
self.dossier_combo = ComboWithAdd(self._add_dossier)
|
||
fl.addRow("Dossier enseignant :", self.dossier_combo)
|
||
self.tiers_check = QCheckBox("Oui")
|
||
self.tiers_check.stateChanged.connect(self._on_tiers_changed)
|
||
fl.addRow("Réalisé par tiers :", self.tiers_check)
|
||
self.detail_tiers_edit = QLineEdit()
|
||
self.detail_tiers_edit.setEnabled(False)
|
||
fl.addRow("Détail tiers :", self.detail_tiers_edit)
|
||
|
||
# ---- Remarques ----
|
||
self._sep(fl)
|
||
self.remarques_edit = QLineEdit()
|
||
fl.addRow("Remarques :", self.remarques_edit)
|
||
|
||
# --- Boutons d'action ---
|
||
btn_layout = QHBoxLayout()
|
||
btn_cancel = QPushButton("Fermer")
|
||
btn_cancel.clicked.connect(self.reject)
|
||
|
||
self.btn_new_form = QPushButton("✚ Nouveau")
|
||
self.btn_new_form.setToolTip("Réinitialiser pour une nouvelle saisie")
|
||
self.btn_new_form.clicked.connect(self._new_form)
|
||
|
||
self.btn_save_new = QPushButton("Enregistrer et nouveau")
|
||
self.btn_save_new.clicked.connect(self._save_and_new)
|
||
|
||
self.btn_save = QPushButton("Enregistrer")
|
||
self.btn_save.setDefault(True)
|
||
self.btn_save.clicked.connect(self._save)
|
||
|
||
btn_layout.addWidget(btn_cancel)
|
||
btn_layout.addWidget(self.btn_new_form)
|
||
btn_layout.addStretch()
|
||
btn_layout.addWidget(self.btn_save_new)
|
||
btn_layout.addWidget(self.btn_save)
|
||
main_layout.addLayout(btn_layout)
|
||
|
||
def _section(self, fl, title):
|
||
lbl = QLabel(f"<b>{title}</b>")
|
||
fl.addRow(lbl)
|
||
|
||
def _sep(self, fl):
|
||
line = QFrame()
|
||
line.setFrameShape(QFrame.HLine)
|
||
line.setStyleSheet("color:#ccc;")
|
||
fl.addRow(line)
|
||
|
||
# -----------------------------------------------------------------------
|
||
# Chargement données de référence
|
||
# -----------------------------------------------------------------------
|
||
|
||
def _load_reference_data(self):
|
||
try:
|
||
self.type_groupe_combo.populate(self.db.get_types_groupe(), "-- Sélectionner --")
|
||
etabs = self.db.get_etablissements()
|
||
self._etab_map = {c: (n, com) for c, n, com in etabs}
|
||
self.etab_combo.populate(
|
||
[(c, f"{n} ({com})" if com else n) for c, n, com in etabs],
|
||
"-- Sélectionner --"
|
||
)
|
||
self.lieux_combo.populate(self.db.get_lieux(), "-- Sélectionner --")
|
||
self.theme_combo.populate(self.db.get_themes(), "-- Sélectionner --")
|
||
self.annul_combo.populate(self.db.get_codes_annulation(), "Non")
|
||
self._set_default(self.annul_combo, "Non")
|
||
self.dossier_combo.populate(self.db.get_type_dossier_ens(), "Non")
|
||
self._set_default(self.dossier_combo, "Non")
|
||
self._reload_animations_list()
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "Erreur chargement", str(e))
|
||
|
||
def _set_default(self, combo_widget, text):
|
||
idx = combo_widget.combo.findText(text)
|
||
if idx >= 0:
|
||
combo_widget.combo.setCurrentIndex(idx)
|
||
|
||
def _reload_animations_list(self):
|
||
self.anim_combo.blockSignals(True)
|
||
self.anim_combo.clear()
|
||
self.anim_combo.addItem("── Nouvelle saisie ──", None)
|
||
try:
|
||
rows = self.db.get_all_animations()
|
||
for code, date_anim, lieux, theme in rows:
|
||
date_str = date_anim.strftime("%d/%m/%Y") if date_anim else "?"
|
||
lieux_str = lieux or "Lieu ?"
|
||
theme_str = theme or "Thème ?"
|
||
label = f"{date_str} | {lieux_str} | {theme_str} [#{code}]"
|
||
self.anim_combo.addItem(label, code)
|
||
except Exception as e:
|
||
QMessageBox.warning(self, "Erreur", f"Impossible de charger les animations : {e}")
|
||
self.anim_combo.blockSignals(False)
|
||
|
||
# -----------------------------------------------------------------------
|
||
# Événements
|
||
# -----------------------------------------------------------------------
|
||
|
||
def _on_anim_selected(self, idx):
|
||
code = self.anim_combo.itemData(idx)
|
||
if code is None:
|
||
self._new_form()
|
||
return
|
||
try:
|
||
data = self.db.get_animation_by_id(code)
|
||
if data:
|
||
self._edit_mode = True
|
||
self._edit_code = code
|
||
self.title_label.setText(f"<h2>Édition animation #{code}</h2>")
|
||
self.btn_save.setText("Mettre à jour")
|
||
self.btn_save_new.setVisible(False)
|
||
self._populate_form(data)
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "Erreur", str(e))
|
||
|
||
def _populate_form(self, data):
|
||
"""Remplit le formulaire avec les données d'une animation existante."""
|
||
if data.get('date_anim'):
|
||
d = data['date_anim']
|
||
self.date_edit.setDate(QDate(d.year, d.month, d.day))
|
||
|
||
duree = data.get('duree_anim', '0h00') or '0h00'
|
||
try:
|
||
if 'h' in duree:
|
||
h, m = duree.split('h')
|
||
self.duree_h.setValue(int(h))
|
||
self.duree_min.setValue(int(m) if m else 0)
|
||
except Exception:
|
||
pass
|
||
|
||
self.prepa_spin.setValue(data.get('prepa_deplacemt') or 0)
|
||
self.animateurs_widget.set_value(data.get('animateurs'))
|
||
self.type_groupe_combo.set_by_data(data.get('code_groupe'))
|
||
self.precisions_groupe_edit.setText(data.get('precisions_type_de_groupe') or '')
|
||
|
||
# Établissement : chercher par nom
|
||
nom_etab = data.get('nom_etablissement') or ''
|
||
for code, (nom, com) in self._etab_map.items():
|
||
if nom == nom_etab:
|
||
self.etab_combo.set_by_data(code)
|
||
break
|
||
|
||
self.enfants_spin.setValue(data.get('nbre_pers_enfants') or 0)
|
||
self.adultes_spin.setValue(data.get('nbre_pers_adultes') or 0)
|
||
self.lieux_combo.set_by_text(data.get('lieux') or '')
|
||
self.precisions_lieux_edit.setText(data.get('precisions_lieux_anim') or '')
|
||
self.accueil_pin_check.setChecked(bool(data.get('accueil_pin')))
|
||
self.theme_detaille_edit.setText(data.get('theme_detaille') or '')
|
||
self.theme_combo.set_by_data(data.get('code_type_anim'))
|
||
self.payant_check.setChecked(bool(data.get('payant')))
|
||
self.annul_combo.set_by_text(data.get('type_annul') or 'Non')
|
||
self.remarques_edit.setText(data.get('remarques') or '')
|
||
self.dossier_combo.set_by_text(data.get('type_dossier_ens') or 'Non')
|
||
realise = bool(data.get('realise_par_tiers'))
|
||
self.tiers_check.setChecked(realise)
|
||
self.detail_tiers_edit.setText(data.get('detail_tiers') or '')
|
||
self.detail_tiers_edit.setEnabled(realise)
|
||
|
||
def _new_form(self):
|
||
self._edit_mode = False
|
||
self._edit_code = None
|
||
self.title_label.setText("<h2>Nouvelle animation</h2>")
|
||
self.btn_save.setText("Enregistrer")
|
||
self.btn_save_new.setVisible(True)
|
||
self.anim_combo.blockSignals(True)
|
||
self.anim_combo.setCurrentIndex(0)
|
||
self.anim_combo.blockSignals(False)
|
||
self._reset_form()
|
||
|
||
def _on_etab_changed(self, idx):
|
||
code = self.etab_combo.combo.itemData(idx)
|
||
if code and code in self._etab_map:
|
||
self.commune_label.setText(self._etab_map[code][1] or "")
|
||
else:
|
||
self.commune_label.setText("")
|
||
|
||
def _on_tiers_changed(self, state):
|
||
self.detail_tiers_edit.setEnabled(state == Qt.Checked)
|
||
|
||
def _update_temps_total(self):
|
||
total = self.duree_h.value() * 60 + self.duree_min.value() + self.prepa_spin.value()
|
||
self.temps_total_label.setText(f"{total} min")
|
||
|
||
def _update_total_pers(self):
|
||
self.total_pers_label.setText(str(self.enfants_spin.value() + self.adultes_spin.value()))
|
||
|
||
# -----------------------------------------------------------------------
|
||
# Capture géométrie sur carte
|
||
# -----------------------------------------------------------------------
|
||
|
||
def _start_point_capture(self, geom_type, on_captured_callback):
|
||
"""
|
||
Lance l'outil de clic sur la carte. geom_type = 'lieu' ou 'etab'.
|
||
Après le clic, appelle on_captured_callback(wkt, srid).
|
||
"""
|
||
canvas = iface.mapCanvas()
|
||
if not canvas:
|
||
QMessageBox.warning(self, "Erreur", "Impossible d'accéder à la carte QGIS.")
|
||
return
|
||
|
||
prev_tool = canvas.mapTool()
|
||
tool = PointCaptureTool(canvas, prev_tool)
|
||
|
||
def on_point(x, y, crs):
|
||
# Convertir en WGS84 (4326) si nécessaire
|
||
wgs84 = QgsCoordinateReferenceSystem("EPSG:4326")
|
||
if crs != wgs84:
|
||
transform = QgsCoordinateTransform(crs, wgs84, QgsProject.instance())
|
||
from qgis.core import QgsPointXY
|
||
pt = transform.transform(x, y)
|
||
x, y = pt.x(), pt.y()
|
||
wkt = f"POINT({x} {y})"
|
||
on_captured_callback(wkt, 4326)
|
||
self.setWindowState(self.windowState() & ~Qt.WindowMinimized | Qt.WindowActive)
|
||
self.activateWindow()
|
||
|
||
tool.pointCaptured.connect(on_point)
|
||
self._point_tool = tool
|
||
|
||
# Minimiser le dialogue et activer l'outil
|
||
self.showMinimized()
|
||
canvas.setMapTool(tool)
|
||
|
||
# -----------------------------------------------------------------------
|
||
# Callbacks ajout nouveaux éléments
|
||
# -----------------------------------------------------------------------
|
||
|
||
def _add_type_groupe(self, widget):
|
||
QMessageBox.information(self, "Info",
|
||
"L'ajout d'un type de groupe nécessite un code entier.\n"
|
||
"Veuillez contacter l'administrateur de la base.")
|
||
|
||
def _add_lieu(self, widget):
|
||
val, ok = QInputDialog.getText(self, "Nouveau lieu", "Nom du lieu :")
|
||
if not ok or not val.strip():
|
||
return
|
||
nom = val.strip()
|
||
|
||
reply = QMessageBox.question(self, "Géométrie",
|
||
"Souhaitez-vous localiser ce lieu sur la carte ?",
|
||
QMessageBox.Yes | QMessageBox.No)
|
||
|
||
if reply == QMessageBox.Yes:
|
||
def on_geom(wkt, srid):
|
||
try:
|
||
code, label = self.db.add_lieux(nom, geom_wkt=wkt, srid=srid)
|
||
widget.add_item(code, label)
|
||
QMessageBox.information(self, "Succès", f"Lieu « {label} » ajouté avec géométrie.")
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "Erreur", str(e))
|
||
self._start_point_capture('lieu', on_geom)
|
||
else:
|
||
try:
|
||
code, label = self.db.add_lieux(nom)
|
||
widget.add_item(code, label)
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "Erreur", str(e))
|
||
|
||
def _add_theme(self, widget):
|
||
val, ok = QInputDialog.getText(self, "Nouveau thème", "Libellé :")
|
||
if ok and val.strip():
|
||
try:
|
||
code, label = self.db.add_theme(val.strip())
|
||
widget.add_item(code, label)
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "Erreur", str(e))
|
||
|
||
def _add_annulation(self, widget):
|
||
val, ok = QInputDialog.getText(self, "Nouveau type d'annulation", "Libellé :")
|
||
if ok and val.strip():
|
||
try:
|
||
code, label = self.db.add_annulation(val.strip())
|
||
widget.add_item(code, label)
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "Erreur", str(e))
|
||
|
||
def _add_dossier(self, widget):
|
||
val, ok = QInputDialog.getText(self, "Nouveau type de dossier", "Libellé :")
|
||
if ok and val.strip():
|
||
try:
|
||
code, label = self.db.add_type_dossier(val.strip())
|
||
widget.add_item(code, label)
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "Erreur", str(e))
|
||
|
||
def _add_etablissement(self, widget):
|
||
nom, ok = QInputDialog.getText(self, "Nouvel établissement", "Nom :")
|
||
if not ok or not nom.strip():
|
||
return
|
||
commune, ok2 = QInputDialog.getText(self, "Nouvel établissement", "Commune :")
|
||
if not ok2:
|
||
return
|
||
nom = nom.strip()
|
||
commune = commune.strip()
|
||
|
||
reply = QMessageBox.question(self, "Géométrie",
|
||
"Souhaitez-vous localiser cet établissement sur la carte ?",
|
||
QMessageBox.Yes | QMessageBox.No)
|
||
|
||
if reply == QMessageBox.Yes:
|
||
def on_geom(wkt, srid):
|
||
try:
|
||
code, label, com = self.db.add_etablissement(nom, commune, geom_wkt=wkt, srid=srid)
|
||
self._etab_map[code] = (label, com)
|
||
display = f"{label} ({com})" if com else label
|
||
widget.add_item(code, display)
|
||
QMessageBox.information(self, "Succès", f"Établissement « {label} » ajouté avec géométrie.")
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "Erreur", str(e))
|
||
self._start_point_capture('etab', on_geom)
|
||
else:
|
||
try:
|
||
code, label, com = self.db.add_etablissement(nom, commune)
|
||
self._etab_map[code] = (label, com)
|
||
display = f"{label} ({com})" if com else label
|
||
widget.add_item(code, display)
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "Erreur", str(e))
|
||
|
||
# -----------------------------------------------------------------------
|
||
# Collecte, validation, enregistrement
|
||
# -----------------------------------------------------------------------
|
||
|
||
def _collect_data(self):
|
||
duree_str = f"{self.duree_h.value()}h{self.duree_min.value():02d}"
|
||
duree_min_total = self.duree_h.value() * 60 + self.duree_min.value()
|
||
temps_total = duree_min_total + self.prepa_spin.value() or None
|
||
|
||
etab_code = self.etab_combo.current_data()
|
||
nom_etab, commune_prov = (None, None)
|
||
if etab_code and etab_code in self._etab_map:
|
||
nom_etab, commune_prov = self._etab_map[etab_code]
|
||
|
||
lieux_txt = self.lieux_combo.current_text() if self.lieux_combo.current_data() else None
|
||
type_annul = self.annul_combo.current_text() if self.annul_combo.current_data() else None
|
||
type_dossier = self.dossier_combo.current_text() if self.dossier_combo.current_data() else None
|
||
realise_tiers = self.tiers_check.isChecked()
|
||
|
||
return {
|
||
"date_anim": self.date_edit.date().toPyDate(),
|
||
"duree_anim": duree_str,
|
||
"animateurs": self.animateurs_widget.get_value(),
|
||
"prepa_deplacemt": self.prepa_spin.value() or None,
|
||
"temps_total": temps_total,
|
||
"code_groupe": self.type_groupe_combo.current_data(),
|
||
"precisions_type_de_groupe": self.precisions_groupe_edit.text().strip() or None,
|
||
"commune_provenance": commune_prov,
|
||
"nom_etablissement": nom_etab,
|
||
"nbre_pers_enfants": self.enfants_spin.value() or None,
|
||
"nbre_pers_adultes": self.adultes_spin.value() or None,
|
||
"nbre_pers_total": (self.enfants_spin.value() + self.adultes_spin.value()) or None,
|
||
"lieux": lieux_txt,
|
||
"precisions_lieux_anim": self.precisions_lieux_edit.text().strip() or None,
|
||
"accueil_pin": self.accueil_pin_check.isChecked(),
|
||
"theme_detaille": self.theme_detaille_edit.text().strip() or None,
|
||
"code_type_anim": self.theme_combo.current_data(),
|
||
"payant": self.payant_check.isChecked(),
|
||
"type_annul": type_annul,
|
||
"remarques": self.remarques_edit.text().strip() or None,
|
||
"type_dossier_ens": type_dossier,
|
||
"realise_par_tiers": realise_tiers,
|
||
"detail_tiers": self.detail_tiers_edit.text().strip() if realise_tiers else None,
|
||
}
|
||
|
||
def _reset_form(self):
|
||
self.date_edit.setDate(QDate.currentDate())
|
||
self.duree_h.setValue(0)
|
||
self.duree_min.setValue(0)
|
||
self.prepa_spin.setValue(0)
|
||
self.animateurs_widget.list_widget.clear()
|
||
self.type_groupe_combo.combo.setCurrentIndex(0)
|
||
self.precisions_groupe_edit.clear()
|
||
self.etab_combo.combo.setCurrentIndex(0)
|
||
self.commune_label.setText("")
|
||
self.enfants_spin.setValue(0)
|
||
self.adultes_spin.setValue(0)
|
||
self.lieux_combo.combo.setCurrentIndex(0)
|
||
self.precisions_lieux_edit.clear()
|
||
self.accueil_pin_check.setChecked(False)
|
||
self.theme_combo.combo.setCurrentIndex(0)
|
||
self.theme_detaille_edit.clear()
|
||
self.payant_check.setChecked(False)
|
||
self.annul_combo.combo.setCurrentIndex(0)
|
||
self.remarques_edit.clear()
|
||
self.dossier_combo.combo.setCurrentIndex(0)
|
||
self.tiers_check.setChecked(False)
|
||
self.detail_tiers_edit.clear()
|
||
|
||
def _save(self):
|
||
try:
|
||
data = self._collect_data()
|
||
if self._edit_mode:
|
||
self.db.update_donnees_animation(self._edit_code, data)
|
||
QMessageBox.information(self, "Succès", f"Animation #{self._edit_code} mise à jour.")
|
||
self._reload_animations_list()
|
||
else:
|
||
code = self.db.get_next_code_animation()
|
||
data['code_animation'] = code
|
||
self.db.insert_donnees_animation(data)
|
||
QMessageBox.information(self, "Succès", f"Animation #{code} enregistrée.")
|
||
self._reload_animations_list()
|
||
self.accept()
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "Erreur", str(e))
|
||
|
||
def _save_and_new(self):
|
||
try:
|
||
data = self._collect_data()
|
||
code = self.db.get_next_code_animation()
|
||
data['code_animation'] = code
|
||
self.db.insert_donnees_animation(data)
|
||
QMessageBox.information(self, "Succès", f"Animation #{code} enregistrée.")
|
||
self._reload_animations_list()
|
||
self._new_form()
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "Erreur", str(e))
|