Bulk-Op Bail-out per Objekt-Typ statt global — DOSSIER-Cascade bleibt aktiv

Regression vom letzten Commit: _on_object_deleted und gestaltung.on_delete
bailten KOMPLETT bei Bulk-Ops. Damit liefen Cascade-Cleanups nicht mehr:
- Wand-Achse geloescht → Wand-Volumen blieb orphaned
- Oeffnungs-Punkt geloescht → Loch in Wand verschwand nicht
- Curve mit Hatch geloescht → Hatch blieb als Geist liegen

Fix: Schnellfilter per UserString-Lookup VOR dem Bail.
- elemente._on_object_deleted: GetUserString(_KEY_TYPE) — nur DOSSIER-
  Sources triggern Cascade. OSM/Swisstopo-Curves haben keinen Type → cheap
  exit, kein per-Event-Overhead. Bulk-Bail entfernt.
- gestaltung.on_delete: bestehender _FILL_KEY/_FILL_OWNER_KEY-Check (line
  1540-1548) filtert non-Hatch-Objekte schon billig. Bulk-Bail entfernt.

Panel-Sync optimiert: _send_state aus on_object_deleted unterdrueckt
waehrend Bulk, einmaliger Push aus _on_command_end.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-20 02:46:21 +02:00
parent b425421fdd
commit 72e24fd512
2 changed files with 26 additions and 11 deletions
+19 -3
View File
@@ -8975,9 +8975,6 @@ def _on_object_deleted(sender, e):
"""
# Waehrend Swisstopo-Import: keine DOSSIER-Metas vorhanden, nur Overhead
if sc.sticky.get("dossier_swisstopo_busy"): return
# Bulk-Delete (z.B. SelAll + Delete bei 6000 OSM-Curves): pro-Event-
# Arbeit waere reiner Overhead. CommandEnd refresht einmalig.
if sc.sticky.get(_BULK_ACTIVE_KEY): return
# Waehrend Move/Rotate/Mirror/Scale: CommandEnd-Pfad uebernimmt das
# Re-Sync. Sonst queued der Delete-Event ueberfluessige Regen-Calls die
# den Pure-Translate-Skip wieder zunichtemachen.
@@ -8987,6 +8984,18 @@ def _on_object_deleted(sender, e):
if sc.sticky.get(_UNDO_ACTIVE_KEY): return
try:
obj = e.TheObject
# Schneller Filter: ohne DOSSIER-Type-UserString gibt es nichts zu
# cascaden. Greift fuer OSM-Curves, Swisstopo-Geometrie, importierte
# Linien etc. → kein per-Event-Overhead bei Bulk-Delete mit 6000
# Fremd-Objekten. Wand-Achsen/Oeffnungs-Punkte/etc behalten ihre
# Cascade auch waehrend Bulk-Ops, sonst zerfaellt die Verknuepfung
# (Volumen orphaned, Oeffnungen in Wand bleiben liegen).
try:
_type_quick = obj.Attributes.GetUserString(_KEY_TYPE)
except Exception:
_type_quick = None
if not _type_quick:
return
meta = _read_meta(obj)
if meta and meta.get("type") in SOURCE_TYPES:
doc = Rhino.RhinoDoc.ActiveDoc
@@ -9048,6 +9057,9 @@ def _on_object_deleted(sender, e):
_queue_regen(wid)
except Exception as ex:
print("[ELEMENTE] del dep regen:", ex)
# Panel-Sync: bei Bulk-Op nur einmal am CommandEnd, sonst
# sofort. Sonst pusht ein Delete von 50 Waenden 50× state.
if not sc.sticky.get(_BULK_ACTIVE_KEY):
b = sc.sticky.get("elemente_bridge")
if b is not None: b._send_state()
except Exception as ex:
@@ -9565,6 +9577,10 @@ def _on_command_end(sender, e):
doc.Views.RedrawEnabled = prev
doc.Views.Redraw()
except Exception: pass
eb = sc.sticky.get("elemente_bridge")
if eb is not None:
try: eb._send_state()
except Exception: pass
gb = sc.sticky.get("gestaltung_bridge")
if gb is not None:
try: gb._send_selection()
+5 -6
View File
@@ -1517,12 +1517,11 @@ def _install_selection_listener(bridge):
Curve aufraeumen damit beim naechsten Toggle keine Geister-Referenz steht."""
if sc.sticky.get("_dossier_undo_active"): return
if sc.sticky.get("_elemente_regen_busy"): return
# Bulk-Delete (SelAll + Delete): pro-Object Hatch-Sync ueberspringen
# — bei 6000 Objekten waere das massive Overhead. Hatch-Verweise
# wuerden zwar nicht aufgeraeumt aber das ist tolerierbar
# (Sticky-Cache laeuft auch ohne Cleanup ab, alte Eintraege bleiben
# nur unsichtbar liegen).
if sc.sticky.get("_dossier_bulk_op_active"): return
# Bulk-Op (SelAll + Delete): KEIN frueher Bail — der UserString-
# Schnellcheck unten (kein _FILL_KEY/_FILL_OWNER_KEY → return)
# filtert OSM/Swisstopo-Curves billig raus. Hatch-gekoppelte Curves
# MUESSEN ihre Hatch mitnehmen, sonst bleiben Geister-Hatches
# liegen (Curve+Hatch zerfallen als Einheit).
obj = args.TheObject
if obj is None or obj.Id in _processing:
return