Files
KAIandClaude Opus 5.5 8253f4f863 Fassung 0.7.1: Liste der Geodienste gehoert zur Auswahl
Nach einem Wechsel von Verfahren oder Landkreis blieb die geholte Liste
stehen; "Ausgewaehlte laden" lud sie dann unter dem Namen der neuen
Auswahl. Jetzt merkt sich die Seitenleiste, fuer welche Auswahl die
Liste geholt wurde, und leert sie bei jedem Wechsel (auch beim stillen
Wiederherstellen aus der Projektdatei). Ein Filter, der die Auswahl
behaelt, laesst sie stehen. Die Meldung nach "Liste holen" nennt beim
Landkreis den Landkreis statt "dieses Verfahren".

Gefunden am 07.10.2026 bei der Aufnahme des Erklaervideos Linkliste.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:12:29 +02:00

209 lines
10 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""Seitenleiste headless pruefen: Zustaende, Filter, Rueckrufe — und als PNG rendern.
Aufruf (macOS, QGIS 4.2 im Bundle; VLN_TOKEN = API-Key aus dem Login):
APP=/Applications/QGIS-final-4_2_0.app; LIB="$APP/Contents/Resources/python3.12"
QT_QPA_PLATFORM=offscreen PROJ_DATA="$APP/Contents/Resources/qgis/proj" \
PYTHONPATH="$LIB:$LIB/lib-dynload:$LIB/site-packages" \
"$APP/Contents/MacOS/python3.12" tools/headless_panel_test.py /tmp/panel.png
Holt die echte Verfahrensliste (GET /tgen) und prueft Zustaende, Filter und Rueckrufe der
Seitenleiste; das PNG zeigt das Layout ohne QGIS-Fenster.
"""
import os, sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from qgis.core import QgsApplication
app = QgsApplication([], True)
QgsApplication.setPrefixPath("/Applications/QGIS-final-4_2_0.app/Contents/MacOS", True)
QgsApplication.setPluginPath("/Applications/QGIS-final-4_2_0.app/Contents/PlugIns/qgis")
app.initQgis()
from qgis.PyQt.QtNetwork import QNetworkProxyFactory
QNetworkProxyFactory.setUseSystemConfiguration(False)
from qgis.PyQt.QtCore import QSize, Qt
from qgis.PyQt.QtWidgets import QScrollArea
from vln_karten.panel import VlnPanel
from vln_karten.api_client import KartenApiClient
ZIEL = sys.argv[1]
FEHLER, GERUFEN = [], []
def pruefe(bed, text):
print((" OK " if bed else " FEHL ") + text)
if not bed:
FEHLER.append(text)
rueckrufe = {name: (lambda *a, n=name: GERUFEN.append((n, a)))
for name in ("login", "logout", "verfahren_gewaehlt", "load_ogc",
"save_edits", "save_style")}
panel = VlnPanel(None, callbacks=rueckrufe)
print("== abgemeldet ==")
pruefe(panel.login_knopf.isVisible() or not panel.logout_knopf.isVisibleTo(panel),
"Anmelde-Knopf sichtbar, Abmelden verborgen")
pruefe(not panel.ogc_knopf.isEnabled() and not panel.combo.isEnabled()
and not panel.speichern_knopf.isEnabled(), "Knoepfe und Auswahl gesperrt")
print("== Issue #1: Rollbalken statt Fensterueberlauf ==")
# Ein QDockWidget reicht die Mindesthoehe seines Inhalts ans Hauptfenster weiter. Ohne
# Rollflaeche wuchs QGIS mit der Seitenleiste und schob seinen unteren Rand aus dem
# Bildschirm (Daniel Helbig, LK Meissen, 14.09.2026).
rolle = panel.widget()
pruefe(isinstance(rolle, QScrollArea), "Inhalt sitzt in einer Rollflaeche")
pruefe(rolle.widgetResizable(), "Inhalt folgt der Breite")
KLEIN = 400
panel.resize(320, KLEIN)
rolle.resize(320, KLEIN)
rolle.widget().adjustSize()
inhalt_hoehe = rolle.widget().sizeHint().height()
pruefe(0 < panel.minimumSizeHint().height() <= KLEIN,
"Dock verlangt hoechstens %d px, aber nicht null (verlangt %d, Inhalt will %d)"
% (KLEIN, panel.minimumSizeHint().height(), inhalt_hoehe))
pruefe(inhalt_hoehe > KLEIN, "Der Testfall greift: der Inhalt ist hoeher als das Dock")
pruefe(rolle.verticalScrollBar().maximum() > 0, "senkrechter Rollbalken wird gebraucht")
pruefe(rolle.horizontalScrollBarPolicy() == Qt.ScrollBarPolicy.ScrollBarAlwaysOff,
"kein waagerechter Rollbalken")
pruefe(rolle.minimumWidth() >= 260, "Mindestbreite bleibt lesbar: %d px" % rolle.minimumWidth())
print("== 0.7.0: Landkreise und „nur lesen“ in der Auswahl, Untergruppe in der Dienstliste ==")
from vln_karten.panel import ist_landkreis
panel.set_angemeldet(True, "pruef@example.org")
panel.set_verfahren([{"vkz": "27027", "name": "TG A", "zugriff": "voll"},
{"vkz": "31005", "name": "TG B", "zugriff": "lesen"}],
[{"vkz": "27", "name": "Landkreis Meißen"}])
texte = [panel.combo.itemText(i) for i in range(panel.combo.count())]
pruefe(texte[1:2] == ["Landkreis Meißen — Linkliste des Landkreises"],
"Landkreis steht oben: %r" % texte[1:2])
pruefe("31005 — TG B (nur lesen)" in texte and "27027 — TG A" in texte,
"Verfahren „nur lesen“ gekennzeichnet: %r" % texte)
pruefe(ist_landkreis("27") and ist_landkreis(100) and not ist_landkreis("27027")
and not ist_landkreis(None) and not ist_landkreis("x"), "ist_landkreis")
panel.set_dienste([{"name": "Denkmal Punkte", "gruppe_name": "Kultur", "untergruppe": "Denkmal",
"herkunft_text": "Landkreis"},
{"name": "Wald", "gruppe_name": "Natur", "herkunft_text": "landesweit"}])
pruefe(panel.dienste_liste.item(0).text().startswith("Denkmal Punkte · Kultur › Denkmal · "),
"Untergruppe in der Dienstliste: %r" % panel.dienste_liste.item(0).text())
pruefe(panel.dienste_liste.item(1).text().startswith("Wald · Natur · "), "ohne Untergruppe wie bisher")
print("== Karten: Wahl hakt vor ==")
from vln_karten.linkliste import KARTEN_VORGABE
panel.set_karten(KARTEN_VORGABE)
pruefe(list(panel.karten_haken) == ["p41", "ngg", "we"] and panel.karten_beschriftung.isVisibleTo(panel),
"je Karte ein Haekchen")
panel.set_dienste([{"name": "Biotope", "gruppe_name": "Natur", "karten": ["ngg"]},
{"name": "Wege", "gruppe_name": "Verkehr", "karten": ["p41", "ngg"]},
{"name": "Bodenwert", "gruppe_name": "Boden", "karten": ["we"]}])
an = lambda: [panel.dienste_liste.item(i).checkState() == Qt.CheckState.Checked
for i in range(panel.dienste_liste.count())]
pruefe(an() == [True, True, True], "ohne Wahl alles angehakt")
panel.karten_haken["p41"].setChecked(True)
pruefe(an() == [False, True, False], "Wege- und Gewaesserplan: nur passende: %r" % an())
panel.karten_haken["we"].setChecked(True)
pruefe(an() == [False, True, True], "zwei Karten zugleich: %r" % an())
panel.set_dienste([{"name": "Neu", "karten": ["we"]}, {"name": "Ohne"}])
pruefe(an() == [True, False], "neue Liste uebernimmt die Kartenwahl: %r" % an())
pruefe("Karten: Wertermittlung" in panel.dienste_liste.item(0).toolTip(), "Karten im Tooltip")
for haken in panel.karten_haken.values():
haken.setChecked(False)
print("== 0.7.1: die Liste gehoert zur Auswahl ==")
# Bis 0.7.0 blieb die Liste nach einem Wechsel stehen; „Ausgewaehlte laden“ lud sie dann unter
# dem Namen der neuen Auswahl (gefunden 07.10.2026 bei der Videoaufnahme).
dienste = [{"name": "LSG", "gruppe_name": "Natur", "herkunft_text": "landesweit"},
{"name": "Biotope Punkte", "gruppe_name": "Natur", "untergruppe": "Biotope",
"herkunft_text": "landesweit"}]
panel.combo.setCurrentIndex(panel.combo.findData("27"))
panel.set_dienste(dienste, "27")
pruefe(panel.dienste_liste.count() == 2, "Liste fuer den Landkreis geholt")
panel.filter_feld.setText("meiß")
pruefe(panel.aktuelles_vkz() == "27" and panel.dienste_liste.count() == 2,
"Filter, der die Auswahl behaelt: Liste bleibt")
panel.filter_feld.clear()
pruefe(panel.aktuelles_vkz() == "27" and panel.dienste_liste.count() == 2, "Filter geleert: Liste bleibt")
panel.combo.setCurrentIndex(panel.combo.findData("27027"))
pruefe(panel.dienste_liste.count() == 0, "Wechsel zum Verfahren leert die Liste")
pruefe("Liste holen" in panel.status_zeile.text(), "Hinweis in der Statuszeile: %r" % panel.status_zeile.text())
panel.set_dienste(dienste) # ohne vkz: gilt fuer die aktuelle Auswahl
panel.waehle_vkz("27027")
pruefe(panel.dienste_liste.count() == 2, "dieselbe Auswahl erneut gesetzt: Liste bleibt")
panel.waehle_vkz("31005")
pruefe(panel.dienste_liste.count() == 0, "stiller Wechsel (Projektdatei) leert ebenfalls")
panel.set_dienste(dienste)
panel.filter_feld.setText("gibtsnicht")
pruefe(panel.dienste_liste.count() == 0, "Filter ohne Treffer: keine Auswahl, keine Liste")
panel.filter_feld.clear()
panel.set_dienste(dienste)
panel.set_angemeldet(False)
pruefe(panel.dienste_liste.count() == 0 and panel._dienste_vkz is None, "Abmelden leert Liste und Zuordnung")
GERUFEN.clear()
if not os.environ.get("VLN_TOKEN"):
print("== Online-Teil uebersprungen (VLN_TOKEN nicht gesetzt) ==")
print("== Ergebnis: %d Fehler ==" % len(FEHLER))
for f in FEHLER:
print(" -", f)
app.exitQgis()
sys.exit(1 if FEHLER else 0)
print("== angemeldet, echte Verfahrensliste ==")
client = KartenApiClient(api_key=os.environ["VLN_TOKEN"])
verfahren = client.get_verfahren()
panel.set_angemeldet(True, "erik.sefkow@…")
panel.set_verfahren(verfahren)
pruefe(panel.ogc_knopf.isEnabled(), "Knoepfe frei")
pruefe(panel.anzahl_eintraege() == len(verfahren) + 1,
"Liste gefuellt: %d Verfahren + Platzhalter" % len(verfahren))
print("== Filter ==")
panel.filter_feld.setText("berb")
treffer = [panel.combo.itemText(i) for i in range(panel.combo.count())][1:]
pruefe(treffer and all("berb" in t.lower() for t in treffer),
"gefiltert auf %d Treffer: %s" % (len(treffer), ", ".join(treffer)[:70]))
panel.filter_feld.setText("gibtsnicht")
pruefe(panel.combo.count() == 1 and panel.combo.currentData() is None,
"kein Treffer -> Platzhalter, kein VKZ")
panel.filter_feld.clear()
pruefe(panel.anzahl_eintraege() == len(verfahren) + 1, "Filter geleert -> Liste wieder voll")
print("== Auswahl + Rueckruf ==")
panel.waehle_vkz("27027")
pruefe(panel.aktuelles_vkz() == "27027", "Wiederherstellen ohne Rueckruf: %s" % panel.aktuelles_vkz())
pruefe(not any(n == "verfahren_gewaehlt" for n, _ in GERUFEN), "waehle_vkz loest keinen Rueckruf aus")
panel.combo.setCurrentIndex(panel.combo.findData(verfahren[0]["vkz"]))
pruefe(any(n == "verfahren_gewaehlt" for n, _ in GERUFEN), "Nutzerauswahl meldet ans Plugin")
panel.waehle_vkz("27027")
print("== Knoepfe ==")
panel.ogc_knopf.click(); panel.speichern_knopf.click(); panel.stil_knopf.click()
namen = [n for n, _ in GERUFEN]
for erwartet in ("load_ogc", "save_edits", "save_style"):
pruefe(erwartet in namen, "Rueckruf %s" % erwartet)
pruefe(not hasattr(panel, "datensatz_knoepfe") and not hasattr(panel, "upload_knopf"),
"kein GeoJSON-Weg mehr in der Seitenleiste")
pruefe(panel.gewaehlte_gruppen() == {"Verfahren", "Vorerhebung", "Maßnahmenblätter"},
"alle Gruppen zunaechst angehakt: %s" % sorted(panel.gewaehlte_gruppen()))
panel.gruppen_haken["Verfahren"].setChecked(False)
pruefe(panel.gewaehlte_gruppen() == {"Vorerhebung", "Maßnahmenblätter"},
"Abwaehlen wirkt: %s" % sorted(panel.gewaehlte_gruppen()))
panel.gruppen_haken["Verfahren"].setChecked(True)
pruefe(not panel.als_vorlage(), "Vorlage-Haken standardmaessig aus")
panel.vorlage_haken.setChecked(True)
pruefe(panel.als_vorlage(), "Vorlage-Haken wirkt")
panel.vorlage_haken.setChecked(False)
print("== Bild ==")
panel.set_status("Stil gespeichert: kas-27027-flaeche (Vorlage)")
panel.widget().widget().resize(QSize(300, 760))
panel.widget().widget().grab().save(ZIEL)
print(" ", ZIEL, os.path.getsize(ZIEL), "Bytes")
app.exitQgis()
print("== Ergebnis: %d Fehler ==" % len(FEHLER))
for f in FEHLER:
print(" -", f)
sys.exit(1 if FEHLER else 0)