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>
209 lines
10 KiB
Python
209 lines
10 KiB
Python
# -*- 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)
|