Warn and reset instead of exiting when a kit manifest is missing
A kit with no manifest under the Sedona home folder called sys.exit(1), tearing down the whole app over one unopenable file. schema now raises MissingManifestError instead, collecting every unresolved kit first so one dialog names them all rather than the user fixing them one reopen at a time. describe_missing_manifests builds the body, pointing at the configured Sedona home and at Preferences. open_file catches it, reports it, and calls the new reset_to_startup_state to return to the just-launched state: no file, empty tree, empty sheet, cleared registries and undo stack. The generic except now resets too, since a half-parsed file previously left current_file_path and a stale root behind. Placing a palette component hits the same loader, where a full reset would be too destructive: it rolls back the <kit> entry it just added, rebuilds the previous registry, and abandons only that placement. schema no longer imports sys or tkinter, so it reports nothing itself and stays testable without a display. base_window_title moves to app_state so the reset can restore the title without duplicating it. README: document the new behaviour, drop the fixed gap, and correct the stale "no undo, no keyboard shortcuts for save" claim. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+63
-1
@@ -53,6 +53,42 @@ def refresh_treeview_from_dom(xml_root):
|
||||
parse_xml_to_tree(tree, root_node, xml_root)
|
||||
|
||||
|
||||
def reset_to_startup_state():
|
||||
"""Returns the app to its just-launched state: no file, empty tree, empty sheet.
|
||||
|
||||
A load that fails part way has already cleared the previous file, so leaving the
|
||||
half-built state on screen would show a tree and a DOM that no longer agree. This
|
||||
is the one place that unwinds all of it.
|
||||
"""
|
||||
app_state.current_file_path = None
|
||||
app_state.xml_root_element = None
|
||||
app_state.current_sheet_parent = None
|
||||
app_state.selected_canvas_tag = None
|
||||
app_state.selected_tree_item_id = None
|
||||
|
||||
app_state.active_components_list.clear()
|
||||
app_state.tree_element_map.clear()
|
||||
app_state.canvas_comp_map.clear()
|
||||
app_state.canvas_tag_by_element.clear()
|
||||
app_state.component_slot_offsets.clear()
|
||||
app_state.final_components_registry.clear()
|
||||
app_state.active_schema_kits.clear()
|
||||
|
||||
undo.reset()
|
||||
app_state.mark_clean()
|
||||
|
||||
if app_state.tree is not None:
|
||||
for item in app_state.tree.get_children():
|
||||
app_state.tree.delete(item)
|
||||
|
||||
if app_state.canvas is not None:
|
||||
app_state.canvas.delete("all")
|
||||
wiresheet.draw_grid()
|
||||
|
||||
if app_state.window is not None:
|
||||
app_state.window.title(app_state.base_window_title())
|
||||
|
||||
|
||||
def open_file():
|
||||
if not app_state.SEDONA_HOME:
|
||||
messagebox.showwarning("Action Blocked", "Cannot load SAX profiles because 'Sedona home folder' configuration is missing or empty.")
|
||||
@@ -98,8 +134,17 @@ def open_file():
|
||||
else:
|
||||
parse_xml_to_tree(tree, root_node, app_state.xml_root_element)
|
||||
|
||||
except schema.MissingManifestError as missing:
|
||||
messagebox.showerror(
|
||||
"Kit manifest missing",
|
||||
f"'{os.path.basename(file_path)}' was not opened.\n\n"
|
||||
+ schema.describe_missing_manifests(missing)
|
||||
+ "\n\nFix the Sedona home folder, then open the file again."
|
||||
)
|
||||
reset_to_startup_state()
|
||||
except Exception as e:
|
||||
messagebox.showerror("Error", f"Failed to parse the file:\n{str(e)}")
|
||||
reset_to_startup_state()
|
||||
|
||||
|
||||
def sync_live_metadata_to_dom():
|
||||
@@ -330,7 +375,24 @@ def add_component(kit_name, type_name, grid_x, grid_y):
|
||||
return None
|
||||
|
||||
# New kit means new types to resolve before the box can be painted.
|
||||
schema.load_schema_kits_and_manifests()
|
||||
try:
|
||||
schema.load_schema_kits_and_manifests()
|
||||
except schema.MissingManifestError as missing:
|
||||
messagebox.showerror(
|
||||
"Kit manifest missing",
|
||||
f"'{kit_name}' was not added.\n\n"
|
||||
+ schema.describe_missing_manifests(missing)
|
||||
)
|
||||
# The kit entry goes back out and the registry is rebuilt from the kits that
|
||||
# were resolvable a moment ago, so only this placement is abandoned.
|
||||
schema_elem = app_state.xml_root_element.find("schema")
|
||||
if schema_elem is not None:
|
||||
schema_elem.remove(kit_added)
|
||||
try:
|
||||
schema.load_schema_kits_and_manifests()
|
||||
except schema.MissingManifestError:
|
||||
reset_to_startup_state()
|
||||
return None
|
||||
|
||||
comp_id = allocate_component_id()
|
||||
comp_name = unique_child_name(parent, type_name)
|
||||
|
||||
Reference in New Issue
Block a user