sedona_editor/schema.py
arda.aydin@ontrol.com.tr 9c283c7eea First Commit
Sedona sax editor AI yardimi ile yaziliyor
2026-08-13 17:59:08 +03:00

164 lines
5.7 KiB
Python

"""Kit manifest loading, slot inheritance, and which slots are worth showing."""
import os
import sys
from tkinter import messagebox
import xml.etree.ElementTree as ET
import app_state
def read_summary_facet(slot_element):
"""Reads a slot's '@summary' facet. Absent means summary, matching manifest convention."""
facets = slot_element.find("facets")
if facets is None:
return True
for bool_facet in facets.findall("bool"):
if bool_facet.get("name") == "summary":
return (bool_facet.get("val", "true").strip().lower() != "false")
return True
def get_slots_with_inheritance(type_name, kit_schemas):
"""Recursively resolves the slots for a given type by traversing its base chain."""
if type_name not in kit_schemas:
kit_prefix = type_name.split("::")[0] if "::" in type_name else type_name
messagebox.showerror("Schema Warning", f"Kit {kit_prefix} is not in Schema selection!")
sys.exit(1)
type_element = kit_schemas[type_name]
base_type = type_element.get("base")
resolved_slots = []
if base_type:
resolved_slots = get_slots_with_inheritance(base_type, kit_schemas)
current_slots = []
for slot in type_element.findall("slot"):
current_slots.append({
"name": slot.get("name"),
"type": slot.get("type"),
"default": slot.get("default", "false"),
"flags": slot.get("flags", ""), # Capture visibility flags ('o' maps to operator/hidden)
"summary": read_summary_facet(slot),
"declared_id": int(slot.get("id"))
})
current_slots.sort(key=lambda s: s["declared_id"])
resolved_slots.extend(current_slots)
return resolved_slots
def compile_schema_registry(manifest_paths):
"""Loads and maps types across multiple kit files, ensuring all dependencies exist."""
kit_schemas = {}
for path in manifest_paths:
try:
tree = ET.parse(path)
root = tree.getroot()
kit_name = root.get("name")
for type_tag in root.findall("type"):
type_name = f"{kit_name}::{type_tag.get('name')}"
kit_schemas[type_name] = type_tag
except Exception as e:
print(f"Error parsing manifest {path}: {e}")
app_state.final_components_registry.clear()
for type_name in kit_schemas.keys():
flat_slots = get_slots_with_inheritance(type_name, kit_schemas)
resolved_type_structure = []
for sequence_id, slot_data in enumerate(flat_slots):
resolved_type_structure.append({
"slot_id": sequence_id,
"name": slot_data["name"],
"type": slot_data["type"],
"default": slot_data["default"],
"flags": slot_data["flags"],
"summary": slot_data["summary"]
})
app_state.final_components_registry[type_name] = resolved_type_structure
def load_schema_kits_and_manifests():
"""Scans the schema block of the SAX file and maps/loads corresponding manifest definitions."""
app_state.active_schema_kits.clear()
if app_state.xml_root_element is None:
return
schema_elem = app_state.xml_root_element.find("schema")
if schema_elem is None:
return
manifest_paths = []
for kit in schema_elem.findall("kit"):
name = kit.get("name")
checksum = kit.get("checksum")
if not name:
continue
app_state.active_schema_kits[name] = checksum
manifest_dir = os.path.join(app_state.SEDONA_HOME, "manifests", name)
manifest_path = None
if checksum:
target_file = os.path.join(manifest_dir, f"{name}-{checksum}.xml")
if os.path.exists(target_file):
manifest_path = target_file
if not manifest_path and os.path.exists(manifest_dir):
files = [f for f in os.listdir(manifest_dir) if f.startswith(f"{name}-") and f.endswith(".xml")]
if files:
files.sort()
manifest_path = os.path.join(manifest_dir, files[-1])
if manifest_path:
manifest_paths.append(manifest_path)
else:
messagebox.showerror("Schema Warning", f"Kit {name} is not in Schema selection!")
sys.exit(1)
compile_schema_registry(manifest_paths)
def get_slots_for_type(type_str, linked_slots=()):
"""
Returns the slots worth painting for a given type, prefixed with double-digit
index tags taken from the manifest so hidden rows leave gaps rather than renumber.
Visibility, in order of precedence:
- a linked slot is always shown, so its wire has a row to anchor to
- '@summary false' hides the slot, even when it is runtime
- runtime slots (no 'c' flag) are shown; they hold the live signal path
- config slots that nothing links to are hidden as clutter
- the 'o' (operator) flag hides a slot outright
"""
if type_str not in app_state.final_components_registry:
return []
slots_list = []
for slot_data in app_state.final_components_registry[type_str]:
slot_name = slot_data["name"]
if not slot_name:
continue
if "o" in slot_data["flags"]:
continue
is_linked = slot_name in linked_slots
if not is_linked:
if not slot_data.get("summary", True):
continue
if "c" in slot_data["flags"]:
continue
# Format to double digits (e.g., 00, 01, 02)
padded_id = f"{slot_data['slot_id']:02d}"
display_label = f"{padded_id}. {slot_name}"
# Keep structural name unchanged for XML lookup inside comp, but pass display label
slots_list.append((slot_name, display_label))
return slots_list