Anzeigefenster immer mit Rahmen, Pfad der Korrektur-Datei im Tab (#56)
Befund aus dem QGIS-Test: Die Bildschirmwahl wirkte nicht, das Fenster erschien immer auf dem Hauptbildschirm. Im Vollbild ließ es sich weder verschieben noch schließen und verdeckte QGIS; nur ein hartes Beenden von QGIS half. Bildschirmwahl und Vollbild entfallen. Das Anzeigefenster öffnet als normales Fenster mit Rahmen; der Bearbeiter schiebt es auf den Bildschirm des Eigentümers und kann es dort maximieren. Größe und Lage werden beim Beenden gemerkt und in der nächsten Sitzung wiederhergestellt (bis zum Neustart von QGIS). Unter den Knöpfen steht jetzt Pfad und Name der Korrektur-Datei, mit Hinweis, solange sie noch nicht angelegt ist oder erst abgefragt wird. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
- Neu: Anzeige für den Eigentümer im Tab „Eigentümer“. „Daten anzeigen“ in der Trefferliste zeigt Name, Anschrift und E-Mail der gewählten Einträge in einem eigenen Fenster – auf einem zweiten Bildschirm im Vollbild, sonst als normales Fenster. Die Sitzung wird von Hand begonnen und beendet; „Anzeige leeren“ entfernt die Daten, ohne das Fenster zu schließen, damit der nächste Eigentümer sie nicht sieht (#56)
|
- Neu: Anzeige für den Eigentümer im Tab „Eigentümer“. „Daten anzeigen“ in der Trefferliste zeigt Name, Anschrift und E-Mail der gewählten Einträge in einem eigenen Fenster mit Rahmen, das der Bearbeiter auf den Bildschirm des Eigentümers schiebt; Größe und Lage gelten bis zum Neustart von QGIS für die nächste Sitzung weiter. Die Sitzung wird von Hand begonnen und beendet; „Anzeige leeren“ entfernt die Daten, ohne das Fenster zu schließen, damit der nächste Eigentümer sie nicht sieht (#56)
|
||||||
- Neu: Angezeigte Daten lassen sich mit „Korrigieren …“ ändern. Die Eigentümerdatei bleibt unverändert; jede Änderung wird mit Zeitpunkt, Konto, Personen-ID, altem und neuem Wert an „<Eigentümerdatei>_korrekturen.csv“ angehängt und sofort angezeigt (#56)
|
- Neu: Angezeigte Daten lassen sich mit „Korrigieren …“ ändern. Die Eigentümerdatei bleibt unverändert; jede Änderung wird mit Zeitpunkt, Konto, Personen-ID, altem und neuem Wert an „<Eigentümerdatei>_korrekturen.csv“ angehängt und sofort angezeigt; Pfad und Name der Korrektur-Datei stehen unter den Knöpfen (#56)
|
||||||
- Neu: Eigentümersuche im Tab „Eigentümer“. Den Serienbriefexport (CSV) von Hand als Layer laden, als Eigentümerdatei wählen, Name und/oder Vorname eingeben: Die Trefferliste zeigt Name, Anschrift, E-Mail, den Wert von PER_RECHTSPERSON (0, 1, 5 oder 9, noch nicht entschlüsselt) und das Kennzeichen „verstorben“. Gleiche Personen mit gleicher Anschrift werden zusammengefasst, Groß-/Kleinschreibung und Umlautschreibweise spielen keine Rolle (#56)
|
- Neu: Eigentümersuche im Tab „Eigentümer“. Den Serienbriefexport (CSV) von Hand als Layer laden, als Eigentümerdatei wählen, Name und/oder Vorname eingeben: Die Trefferliste zeigt Name, Anschrift, E-Mail, den Wert von PER_RECHTSPERSON (0, 1, 5 oder 9, noch nicht entschlüsselt) und das Kennzeichen „verstorben“. Gleiche Personen mit gleicher Anschrift werden zusammengefasst, Groß-/Kleinschreibung und Umlautschreibweise spielen keine Rolle (#56)
|
||||||
- Intern: Die Auswahltabelle aus „Verfahrensgebiete aus Landkreis laden“ (Suchfeld, „Alle auswählen“, Mehrfachauswahl) ist als gemeinsame Funktion herausgelöst und wird von der Eigentümer-Trefferliste mitgenutzt; der Landkreis-Dialog verhält sich unverändert (#56)
|
- Intern: Die Auswahltabelle aus „Verfahrensgebiete aus Landkreis laden“ (Suchfeld, „Alle auswählen“, Mehrfachauswahl) ist als gemeinsame Funktion herausgelöst und wird von der Eigentümer-Trefferliste mitgenutzt; der Landkreis-Dialog verhält sich unverändert (#56)
|
||||||
- Neu: Tab „Eigentümer“ mit Flurstückssuche. Gemarkung (Name oder Nummer) und Flurstücksnummer (z. B. 562 oder 12/3) eingeben, die Treffer werden im Layer „Flurstücke“ ausgewählt und angezoomt. Ohne Nenner werden alle Flurstücke mit diesem Zähler gefunden. Fehlt der Layer „Flurstücke“, weist ein Dialog darauf hin, zuerst Verfahrensgebiet und Flurstücke aus ALKIS zu laden (#56)
|
- Neu: Tab „Eigentümer“ mit Flurstückssuche. Gemarkung (Name oder Nummer) und Flurstücksnummer (z. B. 562 oder 12/3) eingeben, die Treffer werden im Layer „Flurstücke“ ausgewählt und angezoomt. Ohne Nenner werden alle Flurstücke mit diesem Zähler gefunden. Fehlt der Layer „Flurstücke“, weist ein Dialog darauf hin, zuerst Verfahrensgebiet und Flurstücke aus ALKIS zu laden (#56)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
Alle Namen und Anschriften sind erfunden.
|
Alle Namen und Anschriften sind erfunden.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import types
|
|
||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
@@ -15,10 +14,6 @@ ANNA = Eigentuemer(anrede="Frau", titel="Dr.", vorname="Anna", nachname="Beispie
|
|||||||
verstorben=True, rechtsperson=("0",), per_ids=("4711",), konten=("98765",))
|
verstorben=True, rechtsperson=("0",), per_ids=("4711",), konten=("98765",))
|
||||||
|
|
||||||
|
|
||||||
def _rechteck(x, y, b, h):
|
|
||||||
return types.SimpleNamespace(x=lambda: x, y=lambda: y, width=lambda: b, height=lambda: h)
|
|
||||||
|
|
||||||
|
|
||||||
class TestAnzeigetext(unittest.TestCase):
|
class TestAnzeigetext(unittest.TestCase):
|
||||||
|
|
||||||
def test_name_anschrift_email(self):
|
def test_name_anschrift_email(self):
|
||||||
@@ -57,52 +52,39 @@ class TestAnzeigetext(unittest.TestCase):
|
|||||||
self.assertNotIn("Name", text)
|
self.assertNotIn("Name", text)
|
||||||
|
|
||||||
|
|
||||||
class TestBildschirme(unittest.TestCase):
|
class TestFensterOeffnen(unittest.TestCase):
|
||||||
|
|
||||||
def test_vorgabe_ist_nicht_der_qgis_bildschirm(self):
|
def test_normales_fenster_in_standardgroesse(self):
|
||||||
"""Prüft, dass als Vorgabe der erste Bildschirm ohne QGIS gewählt wird, bei nur einem Bildschirm dieser."""
|
"""Prüft, dass das Anzeigefenster ohne gemerkte Lage als normales Fenster mit Rahmen in Standardgröße öffnet, nie im Vollbild."""
|
||||||
a, b, c = object(), object(), object()
|
|
||||||
self.assertEqual(ea.standard_index([a, b, c], a), 1)
|
|
||||||
self.assertEqual(ea.standard_index([a, b], b), 0)
|
|
||||||
self.assertEqual(ea.standard_index([a], a), 0)
|
|
||||||
self.assertEqual(ea.standard_index([], None), 0)
|
|
||||||
|
|
||||||
def test_bildschirm_text(self):
|
|
||||||
"""Prüft, dass ein Bildschirm mit Nummer und Auflösung beschriftet wird."""
|
|
||||||
bildschirm = types.SimpleNamespace(geometry=lambda: _rechteck(0, 0, 1920, 1080))
|
|
||||||
self.assertEqual(ea.bildschirm_text(bildschirm, 2), "Bildschirm 2 (1920 × 1080)")
|
|
||||||
self.assertEqual(ea.bildschirm_text(object(), 3), "Bildschirm 3")
|
|
||||||
|
|
||||||
def test_ohne_qt_anwendung_keine_bildschirme(self):
|
|
||||||
"""Prüft, dass ohne Qt-Anwendung (Mock-Modus) eine leere Bildschirmliste kommt statt eines Fehlers."""
|
|
||||||
self.assertEqual(ea.bildschirme(), [])
|
|
||||||
|
|
||||||
def test_vollbild_auf_gewaehltem_bildschirm(self):
|
|
||||||
"""Prüft, dass das Fenster im Vollbild dem gewählten Bildschirm zugeordnet und auf dessen Fläche gelegt wird."""
|
|
||||||
geo = _rechteck(1920, 0, 1920, 1080)
|
|
||||||
bildschirm = types.SimpleNamespace(geometry=lambda: geo)
|
|
||||||
fenster = MagicMock()
|
fenster = MagicMock()
|
||||||
ea.zeige_auf_bildschirm(fenster, bildschirm, vollbild=True)
|
ea.zeige_anzeigefenster(fenster)
|
||||||
fenster.windowHandle.return_value.setScreen.assert_called_once_with(bildschirm)
|
fenster.resize.assert_called_once_with(*ea.STANDARDGROESSE)
|
||||||
fenster.setGeometry.assert_called_once_with(geo)
|
|
||||||
fenster.showFullScreen.assert_called_once()
|
|
||||||
fenster.showNormal.assert_not_called()
|
|
||||||
|
|
||||||
def test_normales_fenster_mittig(self):
|
|
||||||
"""Prüft, dass auf dem QGIS-Bildschirm ein normales Fenster mittig im freien Bereich öffnet."""
|
|
||||||
bildschirm = types.SimpleNamespace(availableGeometry=lambda: _rechteck(0, 40, 1600, 1000))
|
|
||||||
fenster = MagicMock()
|
|
||||||
ea.zeige_auf_bildschirm(fenster, bildschirm, vollbild=False)
|
|
||||||
fenster.setGeometry.assert_called_once_with(350, 215, 900, 650)
|
|
||||||
fenster.showNormal.assert_called_once()
|
|
||||||
fenster.showFullScreen.assert_not_called()
|
|
||||||
|
|
||||||
def test_ohne_bildschirm_einfach_zeigen(self):
|
|
||||||
"""Prüft, dass ohne bekannten Bildschirm das Fenster einfach gezeigt wird."""
|
|
||||||
fenster = MagicMock()
|
|
||||||
ea.zeige_auf_bildschirm(fenster, None, vollbild=True)
|
|
||||||
fenster.show.assert_called_once()
|
fenster.show.assert_called_once()
|
||||||
fenster.showFullScreen.assert_not_called()
|
fenster.showFullScreen.assert_not_called()
|
||||||
|
fenster.setWindowFlags.assert_not_called()
|
||||||
|
|
||||||
|
def test_gemerkte_lage_wird_wiederhergestellt(self):
|
||||||
|
"""Prüft, dass eine gemerkte Größe und Lage der letzten Sitzung wiederhergestellt wird."""
|
||||||
|
fenster = MagicMock()
|
||||||
|
fenster.restoreGeometry.return_value = True
|
||||||
|
ea.zeige_anzeigefenster(fenster, b"geometrie")
|
||||||
|
fenster.restoreGeometry.assert_called_once_with(b"geometrie")
|
||||||
|
fenster.resize.assert_not_called()
|
||||||
|
fenster.show.assert_called_once()
|
||||||
|
fenster.showFullScreen.assert_not_called()
|
||||||
|
|
||||||
|
def test_unbrauchbare_lage_ergibt_standardgroesse(self):
|
||||||
|
"""Prüft, dass eine nicht wiederherstellbare Lage auf die Standardgröße zurückfällt."""
|
||||||
|
for ergebnis in (False, RuntimeError("kaputt")):
|
||||||
|
with self.subTest(ergebnis=ergebnis):
|
||||||
|
fenster = MagicMock()
|
||||||
|
if isinstance(ergebnis, Exception):
|
||||||
|
fenster.restoreGeometry.side_effect = ergebnis
|
||||||
|
else:
|
||||||
|
fenster.restoreGeometry.return_value = ergebnis
|
||||||
|
ea.zeige_anzeigefenster(fenster, b"alt")
|
||||||
|
fenster.resize.assert_called_once_with(*ea.STANDARDGROESSE)
|
||||||
|
fenster.show.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -192,9 +192,12 @@ class TestTrefferliste(unittest.TestCase):
|
|||||||
|
|
||||||
def _anz_tab(angezeigt=None, anzeige=None, layer_id="csv1"):
|
def _anz_tab(angezeigt=None, anzeige=None, layer_id="csv1"):
|
||||||
tab = EigentuemerTab.__new__(EigentuemerTab)
|
tab = EigentuemerTab.__new__(EigentuemerTab)
|
||||||
for name in ("btn_sitzung", "btn_anzeige_leeren", "btn_korrigieren", "sitzung_label", "bildschirm_combo"):
|
for name in ("btn_sitzung", "btn_anzeige_leeren", "btn_korrigieren", "sitzung_label", "korrektur_label",
|
||||||
|
"eigentuemer_layer_combo"):
|
||||||
setattr(tab, name, MagicMock())
|
setattr(tab, name, MagicMock())
|
||||||
|
tab.eigentuemer_layer_combo.currentData.return_value = layer_id
|
||||||
tab._anzeige = anzeige
|
tab._anzeige = anzeige
|
||||||
|
tab._anzeige_geometrie = None
|
||||||
tab._sitzung_seit = datetime(2026, 10, 6, 9, 5) if anzeige is not None else None
|
tab._sitzung_seit = datetime(2026, 10, 6, 9, 5) if anzeige is not None else None
|
||||||
tab._angezeigt = list(angezeigt or [])
|
tab._angezeigt = list(angezeigt or [])
|
||||||
tab._treffer_layer_id = layer_id
|
tab._treffer_layer_id = layer_id
|
||||||
@@ -206,35 +209,32 @@ def _anz_tab(angezeigt=None, anzeige=None, layer_id="csv1"):
|
|||||||
_BERND = Eigentuemer(vorname="Bernd", nachname="Muster", konten=("300",), per_ids=("8",))
|
_BERND = Eigentuemer(vorname="Bernd", nachname="Muster", konten=("300",), per_ids=("8",))
|
||||||
|
|
||||||
|
|
||||||
@patch.object(et, "zeige_auf_bildschirm")
|
@patch.object(et, "hole_layer", return_value=None)
|
||||||
@patch.object(et, "qgis_bildschirm")
|
@patch.object(et, "zeige_anzeigefenster")
|
||||||
@patch.object(et, "EigentuemerAnzeige")
|
@patch.object(et, "EigentuemerAnzeige")
|
||||||
class TestSitzung(unittest.TestCase):
|
class TestSitzung(unittest.TestCase):
|
||||||
|
|
||||||
def test_sitzung_beginnen_im_vollbild_auf_zweitem_bildschirm(self, anzeige_klasse, qgis, zeige):
|
def test_sitzung_beginnen_oeffnet_leeres_fenster_mit_rahmen(self, anzeige_klasse, zeige, _layer):
|
||||||
"""Prüft, dass „Sitzung beginnen“ ein leeres Anzeigefenster auf dem gewählten Bildschirm öffnet, im Vollbild, wenn QGIS woanders liegt."""
|
"""Prüft, dass „Sitzung beginnen“ ein leeres Anzeigefenster als normales Fenster öffnet (ohne gemerkte Lage beim ersten Mal)."""
|
||||||
tab = _anz_tab()
|
tab = _anz_tab()
|
||||||
zweiter = object()
|
|
||||||
tab.bildschirm_combo.gewaehlter_bildschirm.return_value = zweiter
|
|
||||||
qgis.return_value = object()
|
|
||||||
tab._on_sitzung_umschalten()
|
tab._on_sitzung_umschalten()
|
||||||
anzeige_klasse.assert_called_once_with(tab)
|
anzeige_klasse.assert_called_once_with(tab)
|
||||||
zeige.assert_called_once_with(anzeige_klasse.return_value, zweiter, True)
|
zeige.assert_called_once_with(anzeige_klasse.return_value, None)
|
||||||
self.assertIs(tab._anzeige, anzeige_klasse.return_value)
|
self.assertIs(tab._anzeige, anzeige_klasse.return_value)
|
||||||
self.assertEqual(tab._angezeigt, [])
|
self.assertEqual(tab._angezeigt, [])
|
||||||
tab.btn_sitzung.setText.assert_called_with("Sitzung beenden")
|
tab.btn_sitzung.setText.assert_called_with("Sitzung beenden")
|
||||||
self.assertIn("leer", tab.sitzung_label.setText.call_args[0][0])
|
self.assertIn("leer", tab.sitzung_label.setText.call_args[0][0])
|
||||||
|
|
||||||
def test_auf_qgis_bildschirm_kein_vollbild(self, anzeige_klasse, qgis, zeige):
|
def test_lage_gilt_fuer_naechste_sitzung(self, anzeige_klasse, zeige, _layer):
|
||||||
"""Prüft, dass das Anzeigefenster auf dem QGIS-Bildschirm als normales Fenster öffnet."""
|
"""Prüft, dass Größe und Lage des Fensters beim Beenden gemerkt und in der nächsten Sitzung wiederverwendet werden."""
|
||||||
tab = _anz_tab()
|
tab = _anz_tab()
|
||||||
einziger = object()
|
|
||||||
tab.bildschirm_combo.gewaehlter_bildschirm.return_value = einziger
|
|
||||||
qgis.return_value = einziger
|
|
||||||
tab._sitzung_beginnen()
|
tab._sitzung_beginnen()
|
||||||
self.assertFalse(zeige.call_args[0][2])
|
anzeige_klasse.return_value.saveGeometry.return_value = b"zweiter-bildschirm"
|
||||||
|
tab._sitzung_beenden()
|
||||||
|
tab._sitzung_beginnen()
|
||||||
|
self.assertEqual(zeige.call_args_list[-1][0][1], b"zweiter-bildschirm")
|
||||||
|
|
||||||
def test_daten_anzeigen_beginnt_sitzung_bei_bedarf(self, anzeige_klasse, qgis, zeige):
|
def test_daten_anzeigen_beginnt_sitzung_bei_bedarf(self, anzeige_klasse, zeige, _layer):
|
||||||
"""Prüft, dass „Daten anzeigen“ ohne laufende Sitzung diese beginnt und die Einträge zeigt; die Statuszeile nennt nur die Anzahl."""
|
"""Prüft, dass „Daten anzeigen“ ohne laufende Sitzung diese beginnt und die Einträge zeigt; die Statuszeile nennt nur die Anzahl."""
|
||||||
tab = _anz_tab()
|
tab = _anz_tab()
|
||||||
tab._daten_anzeigen([_ANNA, _BERND])
|
tab._daten_anzeigen([_ANNA, _BERND])
|
||||||
@@ -244,7 +244,7 @@ class TestSitzung(unittest.TestCase):
|
|||||||
self.assertIn("2 Einträge", status)
|
self.assertIn("2 Einträge", status)
|
||||||
self.assertNotIn("Beispiel", status)
|
self.assertNotIn("Beispiel", status)
|
||||||
|
|
||||||
def test_daten_anzeigen_ohne_auswahl(self, anzeige_klasse, qgis, zeige):
|
def test_daten_anzeigen_ohne_auswahl(self, anzeige_klasse, zeige, _layer):
|
||||||
"""Prüft, dass „Daten anzeigen“ ohne Auswahl nur einen Hinweis gibt und keine Sitzung beginnt."""
|
"""Prüft, dass „Daten anzeigen“ ohne Auswahl nur einen Hinweis gibt und keine Sitzung beginnt."""
|
||||||
tab = _anz_tab()
|
tab = _anz_tab()
|
||||||
with patch.object(et, "warning") as warnung:
|
with patch.object(et, "warning") as warnung:
|
||||||
@@ -252,7 +252,7 @@ class TestSitzung(unittest.TestCase):
|
|||||||
warnung.assert_called_once()
|
warnung.assert_called_once()
|
||||||
anzeige_klasse.assert_not_called()
|
anzeige_klasse.assert_not_called()
|
||||||
|
|
||||||
def test_anzeige_leeren_laesst_fenster_offen(self, anzeige_klasse, qgis, zeige):
|
def test_anzeige_leeren_laesst_fenster_offen(self, anzeige_klasse, zeige, _layer):
|
||||||
"""Prüft, dass „Anzeige leeren“ die Daten entfernt, das Fenster aber nicht schließt."""
|
"""Prüft, dass „Anzeige leeren“ die Daten entfernt, das Fenster aber nicht schließt."""
|
||||||
anzeige = MagicMock()
|
anzeige = MagicMock()
|
||||||
tab = _anz_tab(angezeigt=[_ANNA], anzeige=anzeige)
|
tab = _anz_tab(angezeigt=[_ANNA], anzeige=anzeige)
|
||||||
@@ -263,7 +263,7 @@ class TestSitzung(unittest.TestCase):
|
|||||||
self.assertIs(tab._anzeige, anzeige)
|
self.assertIs(tab._anzeige, anzeige)
|
||||||
tab.btn_anzeige_leeren.setEnabled.assert_called_with(False)
|
tab.btn_anzeige_leeren.setEnabled.assert_called_with(False)
|
||||||
|
|
||||||
def test_sitzung_beenden_schliesst_fenster(self, anzeige_klasse, qgis, zeige):
|
def test_sitzung_beenden_schliesst_fenster(self, anzeige_klasse, zeige, _layer):
|
||||||
"""Prüft, dass „Sitzung beenden“ das Anzeigefenster schließt und die angezeigten Daten vergisst."""
|
"""Prüft, dass „Sitzung beenden“ das Anzeigefenster schließt und die angezeigten Daten vergisst."""
|
||||||
anzeige = MagicMock()
|
anzeige = MagicMock()
|
||||||
tab = _anz_tab(angezeigt=[_ANNA], anzeige=anzeige)
|
tab = _anz_tab(angezeigt=[_ANNA], anzeige=anzeige)
|
||||||
@@ -274,21 +274,64 @@ class TestSitzung(unittest.TestCase):
|
|||||||
self.assertEqual(tab._angezeigt, [])
|
self.assertEqual(tab._angezeigt, [])
|
||||||
tab.btn_sitzung.setText.assert_called_with("Sitzung beginnen")
|
tab.btn_sitzung.setText.assert_called_with("Sitzung beginnen")
|
||||||
|
|
||||||
def test_von_aussen_geschlossen_beendet_sitzung(self, anzeige_klasse, qgis, zeige):
|
def test_von_aussen_geschlossen_beendet_sitzung(self, anzeige_klasse, zeige, _layer):
|
||||||
"""Prüft, dass ein von außen geschlossenes Anzeigefenster (z. B. Alt+F4) die Sitzung im Tab beendet."""
|
"""Prüft, dass ein über den Fensterrahmen geschlossenes Anzeigefenster die Sitzung beendet und seine Lage gemerkt wird."""
|
||||||
tab = _anz_tab()
|
tab = _anz_tab()
|
||||||
tab._sitzung_beginnen()
|
tab._sitzung_beginnen()
|
||||||
rueckruf = anzeige_klasse.return_value.beim_schliessen
|
anzeige_klasse.return_value.saveGeometry.return_value = b"lage"
|
||||||
rueckruf()
|
anzeige_klasse.return_value.beim_schliessen()
|
||||||
self.assertIsNone(tab._anzeige)
|
self.assertIsNone(tab._anzeige)
|
||||||
|
self.assertEqual(tab._anzeige_geometrie, b"lage")
|
||||||
|
|
||||||
|
|
||||||
|
class TestKorrekturLabel(unittest.TestCase):
|
||||||
|
|
||||||
|
def _text(self, tab):
|
||||||
|
return tab.korrektur_label.setText.call_args[0][0]
|
||||||
|
|
||||||
|
def test_ohne_eigentuemerdatei(self):
|
||||||
|
"""Prüft, dass ohne Eigentümerdatei unter den Knöpfen steht, dass keine gewählt ist."""
|
||||||
|
tab = _anz_tab(layer_id=None)
|
||||||
|
tab._aktualisiere_korrektur_label()
|
||||||
|
self.assertIn("keine Eigentümerdatei", self._text(tab))
|
||||||
|
|
||||||
|
def test_pfad_neben_der_eigentuemerdatei(self):
|
||||||
|
"""Prüft, dass der Pfad der Korrektur-CSV angezeigt wird, mit Hinweis, solange sie noch nicht angelegt ist."""
|
||||||
|
with tempfile.TemporaryDirectory() as ordner:
|
||||||
|
quelle = "file:///" + os.path.join(ordner, "export.csv").replace(os.sep, "/") + "?type=csv"
|
||||||
|
erwartet = os.path.normpath(os.path.join(ordner, "export_korrekturen.csv"))
|
||||||
|
tab = _anz_tab()
|
||||||
|
with patch.object(et, "hole_layer", return_value=types.SimpleNamespace(source=lambda: quelle)):
|
||||||
|
tab._aktualisiere_korrektur_label()
|
||||||
|
self.assertEqual(os.path.normcase(self._text(tab)),
|
||||||
|
os.path.normcase(f"Korrektur-Datei: {erwartet} (wird beim ersten Speichern angelegt)"))
|
||||||
|
open(erwartet, "w").close()
|
||||||
|
tab._aktualisiere_korrektur_label()
|
||||||
|
self.assertEqual(os.path.normcase(self._text(tab)), os.path.normcase(f"Korrektur-Datei: {erwartet}"))
|
||||||
|
|
||||||
|
def test_ohne_csv_quelle_wird_abgefragt(self):
|
||||||
|
"""Prüft, dass bei einer Quelle ohne CSV angekündigt wird, dass der Speicherort beim ersten Speichern abgefragt wird."""
|
||||||
|
tab = _anz_tab()
|
||||||
|
with patch.object(et, "hole_layer", return_value=types.SimpleNamespace(source=lambda: "memory?geometry=None")):
|
||||||
|
tab._aktualisiere_korrektur_label()
|
||||||
|
self.assertIn("abgefragt", self._text(tab))
|
||||||
|
|
||||||
|
def test_gewaehlter_pfad_wird_angezeigt(self):
|
||||||
|
"""Prüft, dass ein einmal gewählter Speicherort angezeigt wird."""
|
||||||
|
tab = _anz_tab()
|
||||||
|
tab._korrektur_pfade["csv1"] = "D:/Termine/korrekturen.csv"
|
||||||
|
with patch.object(et, "hole_layer", return_value=None):
|
||||||
|
tab._aktualisiere_korrektur_label()
|
||||||
|
self.assertIn(os.path.normpath("D:/Termine/korrekturen.csv"), self._text(tab))
|
||||||
|
|
||||||
|
|
||||||
|
@patch.object(et, "hole_layer", return_value=None)
|
||||||
@patch.object(et, "success")
|
@patch.object(et, "success")
|
||||||
@patch.object(et, "info")
|
@patch.object(et, "info")
|
||||||
@patch.object(et, "warning")
|
@patch.object(et, "warning")
|
||||||
class TestKorrektur(unittest.TestCase):
|
class TestKorrektur(unittest.TestCase):
|
||||||
|
|
||||||
def test_korrektur_wird_festgehalten_und_angezeigt(self, warnung, hinweis, erfolg):
|
def test_korrektur_wird_festgehalten_und_angezeigt(self, warnung, hinweis, erfolg, _layer):
|
||||||
"""Prüft, dass eine Korrektur in die Korrektur-CSV geschrieben, sofort angezeigt und ohne Namen gemeldet wird."""
|
"""Prüft, dass eine Korrektur in die Korrektur-CSV geschrieben, sofort angezeigt und ohne Namen gemeldet wird."""
|
||||||
anzeige = MagicMock()
|
anzeige = MagicMock()
|
||||||
tab = _anz_tab(angezeigt=[_ANNA, _BERND], anzeige=anzeige)
|
tab = _anz_tab(angezeigt=[_ANNA, _BERND], anzeige=anzeige)
|
||||||
@@ -305,7 +348,7 @@ class TestKorrektur(unittest.TestCase):
|
|||||||
self.assertIn("export_korrekturen.csv", meldung)
|
self.assertIn("export_korrekturen.csv", meldung)
|
||||||
self.assertNotIn("Muster", meldung)
|
self.assertNotIn("Muster", meldung)
|
||||||
|
|
||||||
def test_ohne_aenderung_nichts_schreiben(self, warnung, hinweis, erfolg):
|
def test_ohne_aenderung_nichts_schreiben(self, warnung, hinweis, erfolg, _layer):
|
||||||
"""Prüft, dass ein unverändert gespeicherter Dialog nichts schreibt."""
|
"""Prüft, dass ein unverändert gespeicherter Dialog nichts schreibt."""
|
||||||
tab = _anz_tab(angezeigt=[_ANNA], anzeige=MagicMock())
|
tab = _anz_tab(angezeigt=[_ANNA], anzeige=MagicMock())
|
||||||
with patch.object(et, "frage_korrektur", return_value=(0, {"nachname": "Beispiel"})), \
|
with patch.object(et, "frage_korrektur", return_value=(0, {"nachname": "Beispiel"})), \
|
||||||
@@ -314,7 +357,7 @@ class TestKorrektur(unittest.TestCase):
|
|||||||
schreiben.assert_not_called()
|
schreiben.assert_not_called()
|
||||||
hinweis.assert_called_once()
|
hinweis.assert_called_once()
|
||||||
|
|
||||||
def test_abbruch_nichts_schreiben(self, warnung, hinweis, erfolg):
|
def test_abbruch_nichts_schreiben(self, warnung, hinweis, erfolg, _layer):
|
||||||
"""Prüft, dass ein abgebrochener Korrekturdialog nichts schreibt."""
|
"""Prüft, dass ein abgebrochener Korrekturdialog nichts schreibt."""
|
||||||
tab = _anz_tab(angezeigt=[_ANNA], anzeige=MagicMock())
|
tab = _anz_tab(angezeigt=[_ANNA], anzeige=MagicMock())
|
||||||
with patch.object(et, "frage_korrektur", return_value=None), \
|
with patch.object(et, "frage_korrektur", return_value=None), \
|
||||||
@@ -322,7 +365,7 @@ class TestKorrektur(unittest.TestCase):
|
|||||||
tab._on_korrigieren()
|
tab._on_korrigieren()
|
||||||
schreiben.assert_not_called()
|
schreiben.assert_not_called()
|
||||||
|
|
||||||
def test_schreibfehler_warnung_und_anzeige_unveraendert(self, warnung, hinweis, erfolg):
|
def test_schreibfehler_warnung_und_anzeige_unveraendert(self, warnung, hinweis, erfolg, _layer):
|
||||||
"""Prüft, dass bei einem Schreibfehler gewarnt, die Anzeige nicht geändert und der Pfad beim nächsten Mal neu bestimmt wird."""
|
"""Prüft, dass bei einem Schreibfehler gewarnt, die Anzeige nicht geändert und der Pfad beim nächsten Mal neu bestimmt wird."""
|
||||||
anzeige = MagicMock()
|
anzeige = MagicMock()
|
||||||
tab = _anz_tab(angezeigt=[_ANNA], anzeige=anzeige)
|
tab = _anz_tab(angezeigt=[_ANNA], anzeige=anzeige)
|
||||||
@@ -335,7 +378,7 @@ class TestKorrektur(unittest.TestCase):
|
|||||||
self.assertIs(tab._angezeigt[0], _ANNA)
|
self.assertIs(tab._angezeigt[0], _ANNA)
|
||||||
self.assertNotIn("csv1", tab._korrektur_pfade)
|
self.assertNotIn("csv1", tab._korrektur_pfade)
|
||||||
|
|
||||||
def test_ohne_anzeige_keine_korrektur(self, warnung, hinweis, erfolg):
|
def test_ohne_anzeige_keine_korrektur(self, warnung, hinweis, erfolg, _layer):
|
||||||
"""Prüft, dass ohne angezeigte Daten kein Korrekturdialog erscheint."""
|
"""Prüft, dass ohne angezeigte Daten kein Korrekturdialog erscheint."""
|
||||||
tab = _anz_tab()
|
tab = _anz_tab()
|
||||||
with patch.object(et, "frage_korrektur") as dialog:
|
with patch.object(et, "frage_korrektur") as dialog:
|
||||||
|
|||||||
+24
-90
@@ -5,22 +5,23 @@ sieht. Es zeigt ausschließlich Name, Anschrift und E-Mail der vom Bearbeiter
|
|||||||
gewählten Einträge – keine Konten, keine Kennzeichen, keine anderen Treffer.
|
gewählten Einträge – keine Konten, keine Kennzeichen, keine anderen Treffer.
|
||||||
Ohne Inhalt zeigt es nur einen neutralen Platzhalter.
|
Ohne Inhalt zeigt es nur einen neutralen Platzhalter.
|
||||||
|
|
||||||
Liegt das Fenster auf einem anderen Bildschirm als QGIS, öffnet es im Vollbild
|
Das Fenster öffnet immer als normales Fenster mit Rahmen; der Bearbeiter
|
||||||
ohne Rahmen; der Eigentümer kann es nicht versehentlich schließen oder
|
schiebt es selbst auf den Bildschirm des Eigentümers und kann es dort
|
||||||
verschieben. Auf dem QGIS-Bildschirm (z. B. am Notebook ohne zweiten Monitor)
|
maximieren. Eine automatische Bildschirmwahl mit Vollbild hat sich im QGIS-Test
|
||||||
öffnet es als normales Fenster.
|
nicht bewährt: Das Fenster landete stets auf dem Hauptbildschirm und ließ sich
|
||||||
|
im Vollbild weder verschieben noch schließen (siehe ``fallstricke.md``).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import html
|
import html
|
||||||
from typing import Callable, List, Optional, Sequence
|
from typing import Callable, Optional, Sequence
|
||||||
|
|
||||||
from sn_basis.functions.qt_wrapper import QWidget, QVBoxLayout, QLabel, QComboBox, QCoreApplication, Qt
|
from sn_basis.functions.qt_wrapper import QWidget, QVBoxLayout, QLabel, Qt
|
||||||
from sn_basis.functions.qgisui_wrapper import get_main_window
|
|
||||||
|
|
||||||
from sn_verfahrensgebiet.functions.eigentuemer_suche import Eigentuemer
|
from sn_verfahrensgebiet.functions.eigentuemer_suche import Eigentuemer
|
||||||
|
|
||||||
PLATZHALTER = "Datenabgleich"
|
PLATZHALTER = "Datenabgleich"
|
||||||
OHNE_EMAIL = "keine angegeben"
|
OHNE_EMAIL = "keine angegeben"
|
||||||
|
STANDARDGROESSE = (900, 650)
|
||||||
|
|
||||||
|
|
||||||
def _ortsteil(text: str) -> str:
|
def _ortsteil(text: str) -> str:
|
||||||
@@ -91,88 +92,21 @@ class EigentuemerAnzeige(QWidget):
|
|||||||
super().closeEvent(event)
|
super().closeEvent(event)
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
def zeige_anzeigefenster(fenster, geometrie=None) -> None:
|
||||||
# Bildschirme
|
"""Zeigt das Anzeigefenster als normales Fenster mit Rahmen, nie im Vollbild.
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
def bildschirme() -> List[object]:
|
Mit ``geometrie`` (aus ``saveGeometry()`` der letzten Sitzung) erscheint es
|
||||||
"""Alle angeschlossenen Bildschirme (``QScreen``); leer ohne Qt-Anwendung."""
|
wieder dort, wohin der Bearbeiter es geschoben hatte; sonst in
|
||||||
try:
|
Standardgröße an der von Qt gewählten Stelle.
|
||||||
anwendung = QCoreApplication.instance()
|
|
||||||
return list(anwendung.screens()) if anwendung is not None else []
|
|
||||||
except Exception:
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
def qgis_bildschirm() -> Optional[object]:
|
|
||||||
"""Der Bildschirm mit dem QGIS-Hauptfenster, oder ``None``."""
|
|
||||||
try:
|
|
||||||
return get_main_window().screen()
|
|
||||||
except Exception:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def bildschirm_text(bildschirm, nummer: int) -> str:
|
|
||||||
"""Eintrag für die Auswahlliste, z. B. ``Bildschirm 2 (1920 × 1080)``."""
|
|
||||||
try:
|
|
||||||
geo = bildschirm.geometry()
|
|
||||||
return f"Bildschirm {nummer} ({geo.width()} × {geo.height()})"
|
|
||||||
except Exception:
|
|
||||||
return f"Bildschirm {nummer}"
|
|
||||||
|
|
||||||
|
|
||||||
def standard_index(alle: Sequence[object], qgis: Optional[object]) -> int:
|
|
||||||
"""Index des ersten Bildschirms, der nicht der QGIS-Bildschirm ist; sonst 0."""
|
|
||||||
for index, bildschirm in enumerate(alle):
|
|
||||||
if bildschirm is not qgis:
|
|
||||||
return index
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
def zeige_auf_bildschirm(fenster, bildschirm, vollbild: bool) -> None:
|
|
||||||
"""Öffnet ``fenster`` auf ``bildschirm`` – im Vollbild oder mittig als normales Fenster."""
|
|
||||||
if bildschirm is None:
|
|
||||||
fenster.show()
|
|
||||||
return
|
|
||||||
fenster.winId() # erzeugt das native Fenster, damit es einem Bildschirm zugeordnet werden kann
|
|
||||||
griff = fenster.windowHandle()
|
|
||||||
if griff is not None:
|
|
||||||
griff.setScreen(bildschirm)
|
|
||||||
if vollbild:
|
|
||||||
fenster.setGeometry(bildschirm.geometry())
|
|
||||||
fenster.showFullScreen()
|
|
||||||
else:
|
|
||||||
frei = bildschirm.availableGeometry()
|
|
||||||
breite, hoehe = min(900, frei.width()), min(650, frei.height())
|
|
||||||
fenster.setGeometry(frei.x() + (frei.width() - breite) // 2,
|
|
||||||
frei.y() + (frei.height() - hoehe) // 2, breite, hoehe)
|
|
||||||
fenster.showNormal()
|
|
||||||
fenster.raise_()
|
|
||||||
|
|
||||||
|
|
||||||
class BildschirmAuswahl(QComboBox):
|
|
||||||
"""Auswahl des Bildschirms für das Anzeigefenster; wird beim Aufklappen aufgefrischt.
|
|
||||||
|
|
||||||
Vorgabe ist der erste Bildschirm, auf dem QGIS nicht liegt.
|
|
||||||
"""
|
"""
|
||||||
|
wiederhergestellt = False
|
||||||
def aktualisieren(self) -> None:
|
if geometrie is not None:
|
||||||
bisher = self.currentData()
|
try:
|
||||||
alle = bildschirme()
|
wiederhergestellt = bool(fenster.restoreGeometry(geometrie))
|
||||||
self.clear()
|
except Exception:
|
||||||
for nummer, bildschirm in enumerate(alle, start=1):
|
wiederhergestellt = False
|
||||||
self.addItem(bildschirm_text(bildschirm, nummer), bildschirm.name())
|
if not wiederhergestellt:
|
||||||
index = self.findData(bisher) if bisher else -1
|
fenster.resize(*STANDARDGROESSE)
|
||||||
self.setCurrentIndex(index if index >= 0 else standard_index(alle, qgis_bildschirm()))
|
fenster.show()
|
||||||
|
fenster.raise_()
|
||||||
def showPopup(self) -> None:
|
fenster.activateWindow()
|
||||||
self.aktualisieren()
|
|
||||||
super().showPopup()
|
|
||||||
|
|
||||||
def gewaehlter_bildschirm(self) -> Optional[object]:
|
|
||||||
"""Der gewählte ``QScreen`` oder ``None``, wenn es ihn nicht (mehr) gibt."""
|
|
||||||
name = self.currentData()
|
|
||||||
for bildschirm in bildschirme():
|
|
||||||
if bildschirm.name() == name:
|
|
||||||
return bildschirm
|
|
||||||
return None
|
|
||||||
|
|||||||
+63
-34
@@ -8,11 +8,13 @@ Zwei Bereiche:
|
|||||||
- **Eigentümersuche:** Eigentümerdatei (CSV-Layer) wählen, Name und/oder Vorname
|
- **Eigentümersuche:** Eigentümerdatei (CSV-Layer) wählen, Name und/oder Vorname
|
||||||
eingeben, „Suchen“ öffnet die Trefferliste.
|
eingeben, „Suchen“ öffnet die Trefferliste.
|
||||||
Logik: :mod:`sn_verfahrensgebiet.functions.eigentuemer_suche`.
|
Logik: :mod:`sn_verfahrensgebiet.functions.eigentuemer_suche`.
|
||||||
- **Anzeige für den Eigentümer:** Bildschirm wählen, Sitzung beginnen und
|
- **Anzeige für den Eigentümer:** Sitzung beginnen und beenden, Anzeige
|
||||||
beenden, Anzeige leeren, angezeigte Daten korrigieren. „Daten anzeigen“ in
|
leeren, angezeigte Daten korrigieren. „Daten anzeigen“ in der Trefferliste
|
||||||
der Trefferliste füllt das Anzeigefenster (und beginnt bei Bedarf die
|
füllt das Anzeigefenster (und beginnt bei Bedarf die Sitzung). Das Fenster
|
||||||
Sitzung). Korrekturen landen in einer Korrektur-CSV neben der
|
schiebt der Bearbeiter selbst auf den Bildschirm des Eigentümers; Größe und
|
||||||
Eigentümerdatei (:mod:`sn_verfahrensgebiet.functions.eigentuemer_korrektur`).
|
Lage gelten für die nächste Sitzung weiter. Korrekturen landen in einer
|
||||||
|
Korrektur-CSV neben der Eigentümerdatei, deren Pfad unter den Knöpfen steht
|
||||||
|
(:mod:`sn_verfahrensgebiet.functions.eigentuemer_korrektur`).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@@ -44,12 +46,7 @@ from sn_verfahrensgebiet.functions.eigentuemer_korrektur import (
|
|||||||
wende_an,
|
wende_an,
|
||||||
)
|
)
|
||||||
from sn_verfahrensgebiet.ui.eigentuemer_treffer import EigentuemerTrefferFenster
|
from sn_verfahrensgebiet.ui.eigentuemer_treffer import EigentuemerTrefferFenster
|
||||||
from sn_verfahrensgebiet.ui.eigentuemer_anzeige import (
|
from sn_verfahrensgebiet.ui.eigentuemer_anzeige import EigentuemerAnzeige, zeige_anzeigefenster
|
||||||
BildschirmAuswahl,
|
|
||||||
EigentuemerAnzeige,
|
|
||||||
qgis_bildschirm,
|
|
||||||
zeige_auf_bildschirm,
|
|
||||||
)
|
|
||||||
from sn_verfahrensgebiet.ui.eigentuemer_korrektur_dialog import frage_korrektur
|
from sn_verfahrensgebiet.ui.eigentuemer_korrektur_dialog import frage_korrektur
|
||||||
|
|
||||||
_TITEL_SUCHE = "Flurstückssuche"
|
_TITEL_SUCHE = "Flurstückssuche"
|
||||||
@@ -158,18 +155,12 @@ class EigentuemerTab(QWidget):
|
|||||||
titel_anzeige.setStyleSheet("margin-top: 12px;")
|
titel_anzeige.setStyleSheet("margin-top: 12px;")
|
||||||
layout.addWidget(titel_anzeige)
|
layout.addWidget(titel_anzeige)
|
||||||
|
|
||||||
zeile_bildschirm = QHBoxLayout()
|
|
||||||
zeile_bildschirm.addWidget(QLabel("Bildschirm:"))
|
|
||||||
self.bildschirm_combo = BildschirmAuswahl()
|
|
||||||
self.bildschirm_combo.setToolTip(
|
|
||||||
"Bildschirm, den der Eigentümer sieht. Auf einem anderen Bildschirm als QGIS "
|
|
||||||
"öffnet die Anzeige im Vollbild."
|
|
||||||
)
|
|
||||||
zeile_bildschirm.addWidget(self.bildschirm_combo, 1)
|
|
||||||
layout.addLayout(zeile_bildschirm)
|
|
||||||
|
|
||||||
zeile_sitzung = QHBoxLayout()
|
zeile_sitzung = QHBoxLayout()
|
||||||
self.btn_sitzung = QPushButton("Sitzung beginnen")
|
self.btn_sitzung = QPushButton("Sitzung beginnen")
|
||||||
|
self.btn_sitzung.setToolTip(
|
||||||
|
"Öffnet das Anzeigefenster. Es auf den Bildschirm des Eigentümers schieben; "
|
||||||
|
"Größe und Lage gelten für die nächste Sitzung weiter."
|
||||||
|
)
|
||||||
self.btn_anzeige_leeren = QPushButton("Anzeige leeren")
|
self.btn_anzeige_leeren = QPushButton("Anzeige leeren")
|
||||||
self.btn_anzeige_leeren.setToolTip(
|
self.btn_anzeige_leeren.setToolTip(
|
||||||
"Entfernt die Daten aus dem Anzeigefenster, ohne es zu schließen – "
|
"Entfernt die Daten aus dem Anzeigefenster, ohne es zu schließen – "
|
||||||
@@ -187,19 +178,27 @@ class EigentuemerTab(QWidget):
|
|||||||
self.sitzung_label.setWordWrap(True)
|
self.sitzung_label.setWordWrap(True)
|
||||||
layout.addWidget(self.sitzung_label)
|
layout.addWidget(self.sitzung_label)
|
||||||
|
|
||||||
|
self.korrektur_label = QLabel()
|
||||||
|
self.korrektur_label.setWordWrap(True)
|
||||||
|
self.korrektur_label.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
|
||||||
|
layout.addWidget(self.korrektur_label)
|
||||||
|
|
||||||
self.btn_sitzung.clicked.connect(self._on_sitzung_umschalten)
|
self.btn_sitzung.clicked.connect(self._on_sitzung_umschalten)
|
||||||
self.btn_anzeige_leeren.clicked.connect(self._on_anzeige_leeren)
|
self.btn_anzeige_leeren.clicked.connect(self._on_anzeige_leeren)
|
||||||
self.btn_korrigieren.clicked.connect(self._on_korrigieren)
|
self.btn_korrigieren.clicked.connect(self._on_korrigieren)
|
||||||
|
self.eigentuemer_layer_combo.currentIndexChanged.connect(
|
||||||
|
lambda _index: self._aktualisiere_korrektur_label()
|
||||||
|
)
|
||||||
|
|
||||||
self._trefferfenster = None
|
self._trefferfenster = None
|
||||||
self._treffer_layer_id = None
|
self._treffer_layer_id = None
|
||||||
self._anzeige = None
|
self._anzeige = None
|
||||||
|
self._anzeige_geometrie = None
|
||||||
self._sitzung_seit = None
|
self._sitzung_seit = None
|
||||||
self._angezeigt = []
|
self._angezeigt = []
|
||||||
self._anzeige_layer_id = None
|
self._anzeige_layer_id = None
|
||||||
self._korrektur_pfade = {}
|
self._korrektur_pfade = {}
|
||||||
self.eigentuemer_layer_combo.aktualisieren()
|
self.eigentuemer_layer_combo.aktualisieren()
|
||||||
self.bildschirm_combo.aktualisieren()
|
|
||||||
self._aktualisiere_sitzungsstatus()
|
self._aktualisiere_sitzungsstatus()
|
||||||
|
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
@@ -292,12 +291,10 @@ class EigentuemerTab(QWidget):
|
|||||||
self._sitzung_beenden()
|
self._sitzung_beenden()
|
||||||
|
|
||||||
def _sitzung_beginnen(self) -> None:
|
def _sitzung_beginnen(self) -> None:
|
||||||
"""Öffnet das Anzeigefenster leer auf dem gewählten Bildschirm."""
|
"""Öffnet das Anzeigefenster leer, mit Rahmen, an der Stelle der letzten Sitzung."""
|
||||||
bildschirm = self.bildschirm_combo.gewaehlter_bildschirm()
|
|
||||||
anzeige = EigentuemerAnzeige(self)
|
anzeige = EigentuemerAnzeige(self)
|
||||||
anzeige.beim_schliessen = self._anzeige_wurde_geschlossen
|
anzeige.beim_schliessen = self._anzeige_wurde_geschlossen
|
||||||
vollbild = bildschirm is not None and bildschirm is not qgis_bildschirm()
|
zeige_anzeigefenster(anzeige, self._anzeige_geometrie)
|
||||||
zeige_auf_bildschirm(anzeige, bildschirm, vollbild)
|
|
||||||
self._anzeige = anzeige
|
self._anzeige = anzeige
|
||||||
self._sitzung_seit = datetime.now()
|
self._sitzung_seit = datetime.now()
|
||||||
self._angezeigt = []
|
self._angezeigt = []
|
||||||
@@ -312,6 +309,11 @@ class EigentuemerTab(QWidget):
|
|||||||
anzeige.close()
|
anzeige.close()
|
||||||
|
|
||||||
def _anzeige_wurde_geschlossen(self) -> None:
|
def _anzeige_wurde_geschlossen(self) -> None:
|
||||||
|
if self._anzeige is not None:
|
||||||
|
try:
|
||||||
|
self._anzeige_geometrie = self._anzeige.saveGeometry()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
self._anzeige = None
|
self._anzeige = None
|
||||||
self._sitzung_seit = None
|
self._sitzung_seit = None
|
||||||
self._angezeigt = []
|
self._angezeigt = []
|
||||||
@@ -349,6 +351,36 @@ class EigentuemerTab(QWidget):
|
|||||||
inhalt = "leer" if not anzahl else ("1 Eintrag" if anzahl == 1 else f"{anzahl} Einträge")
|
inhalt = "leer" if not anzahl else ("1 Eintrag" if anzahl == 1 else f"{anzahl} Einträge")
|
||||||
text = f"Sitzung seit {self._sitzung_seit:%H:%M} Uhr – Anzeige: {inhalt}"
|
text = f"Sitzung seit {self._sitzung_seit:%H:%M} Uhr – Anzeige: {inhalt}"
|
||||||
self.sitzung_label.setText(text)
|
self.sitzung_label.setText(text)
|
||||||
|
self._aktualisiere_korrektur_label()
|
||||||
|
|
||||||
|
def _korrektur_layer_id(self):
|
||||||
|
"""Eigentümerdatei, zu der Korrekturen gehören: die angezeigte, sonst die gesuchte, sonst die gewählte."""
|
||||||
|
return self._anzeige_layer_id or self._treffer_layer_id or self.eigentuemer_layer_combo.currentData()
|
||||||
|
|
||||||
|
def _korrektur_vorschau(self):
|
||||||
|
"""Pfad der Korrektur-CSV ohne Rückfrage, oder ``None``, wenn er erst beim Speichern erfragt wird."""
|
||||||
|
layer_id = self._korrektur_layer_id()
|
||||||
|
if layer_id in self._korrektur_pfade:
|
||||||
|
return self._korrektur_pfade[layer_id]
|
||||||
|
layer = hole_layer(layer_id)
|
||||||
|
vorschlag = korrektur_pfad(layer.source()) if layer is not None else None
|
||||||
|
ordner = os.path.dirname(vorschlag) if vorschlag else ""
|
||||||
|
if vorschlag and os.path.isdir(ordner) and os.access(ordner, os.W_OK):
|
||||||
|
return vorschlag
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _aktualisiere_korrektur_label(self) -> None:
|
||||||
|
"""Zeigt unter den Knöpfen, wohin Korrekturen geschrieben werden."""
|
||||||
|
if not self._korrektur_layer_id():
|
||||||
|
text = "Korrektur-Datei: – (keine Eigentümerdatei gewählt)"
|
||||||
|
else:
|
||||||
|
pfad = self._korrektur_vorschau()
|
||||||
|
if pfad is None:
|
||||||
|
text = "Korrektur-Datei: wird beim ersten Speichern abgefragt"
|
||||||
|
else:
|
||||||
|
zusatz = "" if os.path.exists(pfad) else " (wird beim ersten Speichern angelegt)"
|
||||||
|
text = f"Korrektur-Datei: {os.path.normpath(pfad)}{zusatz}"
|
||||||
|
self.korrektur_label.setText(text)
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# Korrekturen
|
# Korrekturen
|
||||||
@@ -382,6 +414,7 @@ class EigentuemerTab(QWidget):
|
|||||||
self._angezeigt[index] = wende_an(eintrag, aenderungen)
|
self._angezeigt[index] = wende_an(eintrag, aenderungen)
|
||||||
if self._anzeige is not None:
|
if self._anzeige is not None:
|
||||||
self._anzeige.zeige(self._angezeigt)
|
self._anzeige.zeige(self._angezeigt)
|
||||||
|
self._aktualisiere_korrektur_label()
|
||||||
anzahl = len(aenderungen)
|
anzahl = len(aenderungen)
|
||||||
text = "1 Änderung" if anzahl == 1 else f"{anzahl} Änderungen"
|
text = "1 Änderung" if anzahl == 1 else f"{anzahl} Änderungen"
|
||||||
success(_TITEL_ANZEIGE, f"{text} in „{os.path.basename(pfad)}“ festgehalten.")
|
success(_TITEL_ANZEIGE, f"{text} in „{os.path.basename(pfad)}“ festgehalten.")
|
||||||
@@ -394,14 +427,10 @@ class EigentuemerTab(QWidget):
|
|||||||
für die Eigentümerdatei, solange der Tab besteht.
|
für die Eigentümerdatei, solange der Tab besteht.
|
||||||
"""
|
"""
|
||||||
layer_id = self._anzeige_layer_id
|
layer_id = self._anzeige_layer_id
|
||||||
if layer_id in self._korrektur_pfade:
|
pfad = self._korrektur_vorschau() if layer_id == self._korrektur_layer_id() else None
|
||||||
return self._korrektur_pfade[layer_id]
|
if pfad is None:
|
||||||
layer = hole_layer(layer_id)
|
layer = hole_layer(layer_id)
|
||||||
vorschlag = korrektur_pfad(layer.source()) if layer is not None else None
|
vorschlag = korrektur_pfad(layer.source()) if layer is not None else None
|
||||||
ordner = os.path.dirname(vorschlag) if vorschlag else ""
|
|
||||||
if vorschlag and os.path.isdir(ordner) and os.access(ordner, os.W_OK):
|
|
||||||
pfad = vorschlag
|
|
||||||
else:
|
|
||||||
pfad, _ = QFileDialog.getSaveFileName(
|
pfad, _ = QFileDialog.getSaveFileName(
|
||||||
self, "Korrektur-CSV wählen", vorschlag or os.path.expanduser("~"), "CSV-Dateien (*.csv)"
|
self, "Korrektur-CSV wählen", vorschlag or os.path.expanduser("~"), "CSV-Dateien (*.csv)"
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user