Eigentümersuche mit Trefferliste im Tab „Eigentümer“ (#56)
Eigentümerdatei (CSV-Layer mit Nachname/Vorname) wählen, Name und/oder Vorname eingeben: Eine nicht modale Trefferliste zeigt Name, Anschrift, E-Mail und die Kennzeichen „verstorben“/„Rechtsperson“. Gleiche Personen mit gleicher Anschrift werden zusammengefasst; Groß-/Kleinschreibung und Umlautschreibweise spielen keine Rolle. Von QGIS als Zahl gelesene PLZ bekommen ihre führende Null zurück. Meldungen enthalten keine Namen. Die Auswahltabelle aus „Verfahrensgebiete aus Landkreis laden“ ist als baue_auswahltabelle herausgelöst und wird von der Trefferliste mitgenutzt. Zweiter Schritt von #56; Anzeigefenster und Korrekturen folgen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
"""sn_verfahrensgebiet/ui/eigentuemer_treffer.py – Trefferliste der Eigentümersuche (#56).
|
||||
|
||||
Nicht modales Fenster für den Bearbeiter. Es zeigt die zusammengefassten
|
||||
Treffer mit den Kennzeichen „verstorben“ und „Rechtsperson“ und erlaubt die
|
||||
Mehrfachauswahl. Die Tabelle kommt aus
|
||||
:func:`~sn_verfahrensgebiet.functions.verfahrensgebiet_dialoge.baue_auswahltabelle`,
|
||||
dieselbe wie bei „Verfahrensgebiete aus Landkreis laden“.
|
||||
"""
|
||||
|
||||
from typing import List, Sequence, Tuple
|
||||
|
||||
from sn_basis.functions.qt_wrapper import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton
|
||||
|
||||
from sn_verfahrensgebiet.functions.eigentuemer_suche import Eigentuemer
|
||||
from sn_verfahrensgebiet.functions.verfahrensgebiet_dialoge import (
|
||||
baue_auswahltabelle,
|
||||
ausgewaehlte_indizes,
|
||||
)
|
||||
|
||||
SPALTENKOEPFE = ["Name", "Anschrift", "E-Mail", "Hinweis"]
|
||||
|
||||
|
||||
def trefferzeile(eigentuemer: Eigentuemer) -> Tuple[str, str, str, str]:
|
||||
"""Spaltentexte eines Treffers in der Reihenfolge von :data:`SPALTENKOEPFE`."""
|
||||
return (
|
||||
eigentuemer.name,
|
||||
eigentuemer.anschrift,
|
||||
", ".join(eigentuemer.emails),
|
||||
eigentuemer.hinweise,
|
||||
)
|
||||
|
||||
|
||||
class EigentuemerTrefferFenster(QDialog):
|
||||
"""Trefferliste der Eigentümersuche; bleibt offen, während weitergesucht wird."""
|
||||
|
||||
def __init__(self, treffer: Sequence[Eigentuemer], parent=None):
|
||||
super().__init__(parent)
|
||||
self.treffer: List[Eigentuemer] = list(treffer)
|
||||
self.setWindowTitle("Eigentümersuche – Treffer")
|
||||
self.setModal(False)
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
anzahl = len(self.treffer)
|
||||
layout.addWidget(QLabel("1 Eintrag gefunden." if anzahl == 1 else f"{anzahl} Einträge gefunden."))
|
||||
|
||||
self.tabelle = baue_auswahltabelle(
|
||||
layout,
|
||||
SPALTENKOEPFE,
|
||||
[trefferzeile(e) for e in self.treffer],
|
||||
platzhalter="Name, Ort oder Hinweis …",
|
||||
)
|
||||
self.tabelle.resizeColumnsToContents()
|
||||
if anzahl == 1:
|
||||
self.tabelle.selectRow(0)
|
||||
|
||||
knoepfe = QHBoxLayout()
|
||||
knoepfe.addStretch()
|
||||
self.btn_schliessen = QPushButton("Schließen")
|
||||
self.btn_schliessen.clicked.connect(self.close)
|
||||
knoepfe.addWidget(self.btn_schliessen)
|
||||
layout.addLayout(knoepfe)
|
||||
|
||||
self.resize(760, 420)
|
||||
|
||||
def ausgewaehlte_eigentuemer(self) -> List[Eigentuemer]:
|
||||
"""Die in der Tabelle ausgewählten Treffer, in der Reihenfolge der Trefferliste."""
|
||||
return [self.treffer[i] for i in ausgewaehlte_indizes(self.tabelle)]
|
||||
+112
-5
@@ -1,12 +1,17 @@
|
||||
"""sn_verfahrensgebiet/ui/tabs/eigentuemer_tab.py – Tab „Eigentümer“ (#56).
|
||||
|
||||
Enthält die Flurstückssuche: Gemarkung (Name oder Nummer) und Flurstücksnummer
|
||||
eingeben, „Suchen“ wählt die Treffer im Layer „Flurstücke“ aus und zoomt hin.
|
||||
Die Suchlogik liegt in :mod:`sn_verfahrensgebiet.functions.flurstueck_suche`.
|
||||
Zwei Bereiche:
|
||||
|
||||
- **Flurstückssuche:** Gemarkung (Name oder Nummer) und Flurstücksnummer
|
||||
eingeben, „Suchen“ wählt die Treffer im Layer „Flurstücke“ aus und zoomt hin.
|
||||
Logik: :mod:`sn_verfahrensgebiet.functions.flurstueck_suche`.
|
||||
- **Eigentümersuche:** Eigentümerdatei (CSV-Layer) wählen, Name und/oder Vorname
|
||||
eingeben, „Suchen“ öffnet die Trefferliste.
|
||||
Logik: :mod:`sn_verfahrensgebiet.functions.eigentuemer_suche`.
|
||||
"""
|
||||
|
||||
from sn_basis.functions.qt_wrapper import (
|
||||
QWidget, QVBoxLayout, QHBoxLayout, QGridLayout, QLabel, QLineEdit, QPushButton, Qt,
|
||||
QWidget, QVBoxLayout, QHBoxLayout, QGridLayout, QLabel, QLineEdit, QPushButton, QComboBox, Qt,
|
||||
)
|
||||
from sn_basis.functions.qgisui_wrapper import iface
|
||||
from sn_basis.functions.dialog_wrapper import show_info_dialog
|
||||
@@ -17,12 +22,41 @@ from sn_verfahrensgebiet.functions.flurstueck_suche import (
|
||||
FlurstueckSucheFehler,
|
||||
KeinFlurstueckslayer,
|
||||
)
|
||||
from sn_verfahrensgebiet.functions.eigentuemer_suche import (
|
||||
eigentuemerlayer_im_projekt,
|
||||
hole_layer,
|
||||
suche_eigentuemer,
|
||||
EigentuemerSucheFehler,
|
||||
)
|
||||
from sn_verfahrensgebiet.ui.eigentuemer_treffer import EigentuemerTrefferFenster
|
||||
|
||||
_TITEL_SUCHE = "Flurstückssuche"
|
||||
_TITEL_EIGENTUEMER = "Eigentümersuche"
|
||||
|
||||
|
||||
class EigentuemerLayerAuswahl(QComboBox):
|
||||
"""Auswahl der Eigentümerdatei; zeigt nur Layer mit den Spalten Nachname und Vorname.
|
||||
|
||||
Die Liste wird beim Aufklappen neu aufgebaut, damit eine gerade geladene CSV
|
||||
ohne Projektsignale erscheint.
|
||||
"""
|
||||
|
||||
def aktualisieren(self) -> None:
|
||||
"""Baut die Liste neu auf und behält die bisherige Auswahl, solange es den Layer noch gibt."""
|
||||
bisher = self.currentData()
|
||||
self.clear()
|
||||
for layer in eigentuemerlayer_im_projekt():
|
||||
self.addItem(layer.name(), layer.id())
|
||||
index = self.findData(bisher) if bisher else -1
|
||||
self.setCurrentIndex(index if index >= 0 else 0)
|
||||
|
||||
def showPopup(self) -> None:
|
||||
self.aktualisieren()
|
||||
super().showPopup()
|
||||
|
||||
|
||||
class EigentuemerTab(QWidget):
|
||||
"""Tab für Flurstückssuche und (später) Eigentümerabgleich.
|
||||
"""Tab für Flurstückssuche und Eigentümersuche.
|
||||
|
||||
Attributes:
|
||||
tab_title: Anzeigetitel des Tabs ("Eigentümer")
|
||||
@@ -63,6 +97,43 @@ class EigentuemerTab(QWidget):
|
||||
self.gemarkung_edit.returnPressed.connect(self._on_flurstueck_suchen)
|
||||
self.flurstueck_edit.returnPressed.connect(self._on_flurstueck_suchen)
|
||||
|
||||
titel_eigentuemer = QLabel("<b>Eigentümersuche</b>")
|
||||
titel_eigentuemer.setStyleSheet("margin-top: 12px;")
|
||||
layout.addWidget(titel_eigentuemer)
|
||||
|
||||
raster_eig = QGridLayout()
|
||||
raster_eig.addWidget(QLabel("Eigentümerdatei:"), 0, 0)
|
||||
self.eigentuemer_layer_combo = EigentuemerLayerAuswahl()
|
||||
self.eigentuemer_layer_combo.setToolTip(
|
||||
"CSV-Layer mit den Spalten Nachname und Vorname (Serienbriefexport). "
|
||||
"Die CSV von Hand ins Projekt laden; die Liste wird beim Aufklappen aktualisiert."
|
||||
)
|
||||
raster_eig.addWidget(self.eigentuemer_layer_combo, 0, 1)
|
||||
raster_eig.addWidget(QLabel("Name:"), 1, 0)
|
||||
self.nachname_edit = QLineEdit()
|
||||
raster_eig.addWidget(self.nachname_edit, 1, 1)
|
||||
raster_eig.addWidget(QLabel("Vorname:"), 2, 0)
|
||||
self.vorname_edit = QLineEdit()
|
||||
raster_eig.addWidget(self.vorname_edit, 2, 1)
|
||||
layout.addLayout(raster_eig)
|
||||
|
||||
zeile_eig_suchen = QHBoxLayout()
|
||||
zeile_eig_suchen.addStretch()
|
||||
self.btn_eigentuemer_suchen = QPushButton("Suchen")
|
||||
self.btn_eigentuemer_suchen.setToolTip(
|
||||
"Findet Einträge, deren Name und Vorname die Eingaben enthalten. "
|
||||
"Gleiche Personen mit gleicher Anschrift werden zusammengefasst."
|
||||
)
|
||||
zeile_eig_suchen.addWidget(self.btn_eigentuemer_suchen)
|
||||
layout.addLayout(zeile_eig_suchen)
|
||||
|
||||
self.btn_eigentuemer_suchen.clicked.connect(self._on_eigentuemer_suchen)
|
||||
self.nachname_edit.returnPressed.connect(self._on_eigentuemer_suchen)
|
||||
self.vorname_edit.returnPressed.connect(self._on_eigentuemer_suchen)
|
||||
|
||||
self._trefferfenster = None
|
||||
self.eigentuemer_layer_combo.aktualisieren()
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
def _on_flurstueck_suchen(self) -> None:
|
||||
@@ -102,3 +173,39 @@ class EigentuemerTab(QWidget):
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def _on_eigentuemer_suchen(self) -> None:
|
||||
"""Sucht in der gewählten Eigentümerdatei und zeigt die Trefferliste.
|
||||
|
||||
Meldungen enthalten bewusst keine Namen (Datenschutz).
|
||||
"""
|
||||
layer = hole_layer(self.eigentuemer_layer_combo.currentData())
|
||||
if layer is None:
|
||||
self.eigentuemer_layer_combo.aktualisieren()
|
||||
layer = hole_layer(self.eigentuemer_layer_combo.currentData())
|
||||
if layer is None:
|
||||
warning(
|
||||
_TITEL_EIGENTUEMER,
|
||||
"Keine Eigentümerdatei gewählt. Bitte den Serienbriefexport (CSV) "
|
||||
"als Layer laden und hier auswählen.",
|
||||
)
|
||||
return
|
||||
|
||||
try:
|
||||
treffer = suche_eigentuemer(layer, self.nachname_edit.text(), self.vorname_edit.text())
|
||||
except EigentuemerSucheFehler as exc:
|
||||
warning(_TITEL_EIGENTUEMER, str(exc))
|
||||
return
|
||||
|
||||
if not treffer:
|
||||
info(_TITEL_EIGENTUEMER, "Keine passenden Einträge gefunden.")
|
||||
return
|
||||
self._zeige_treffer(treffer)
|
||||
|
||||
def _zeige_treffer(self, treffer) -> None:
|
||||
"""Ersetzt eine offene Trefferliste durch die neue."""
|
||||
alt = getattr(self, "_trefferfenster", None)
|
||||
if alt is not None:
|
||||
alt.close()
|
||||
self._trefferfenster = EigentuemerTrefferFenster(treffer, self)
|
||||
self._trefferfenster.show()
|
||||
|
||||
Reference in New Issue
Block a user