Tree popup: act on the component as it is now, so tree delete is undoable on a device

Right-clicking a tree row selects it, and on a device that reopens the
sheet and rebuilds the DOM after the popup captured the row's element.
Delete then ran on a stale element: the device delete went through but
no undo step was recorded. Popup actions now look the component up by
id when they run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-06 20:14:51 +03:00
co-authored by Claude Opus 5.5
parent 8411f0c9ae
commit 8b21c5f389
2 changed files with 31 additions and 10 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ so later rebinding would only ever be seen by the module that did it.
import configparser
import os
VERSION = "0.0.0.151"
VERSION = "0.0.0.152"
PROPERTIES_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "editor.properties")
DEFAULT_GRID_SIZE = 10
DEFAULT_ADD_TIMESTAMP = True
+30 -9
View File
@@ -216,6 +216,27 @@ def refresh_all_views():
close_editor_panel(force=True)
def current_element(comp):
"""The element standing for `comp` in the document now.
On a device, selecting a tree row opens its sheet, which reads the DOM afresh after
a right-click has already picked the row's element. The same component is then a
new element with the same id; acting on the old one would leave the document, and
undo, holding something other than what the device just did.
"""
root = app_state.xml_root_element
if root is None or not app_state.live_mode:
return comp
if any(element is comp for element in root.iter()):
return comp
comp_id = comp.get("id")
if comp_id is not None:
for element in root.iter():
if element.tag in ("app", "comp") and element.get("id") == comp_id:
return element
return comp
def _component_in_document(comp):
root = app_state.xml_root_element
if root is None:
@@ -1603,46 +1624,46 @@ def fill_component_popup(menu, comp):
menu.delete(0, tk.END)
menu.add_command(
label="Properties",
command=lambda: show_properties(comp),
command=lambda: show_properties(current_element(comp)),
)
menu.add_command(
label="Link View",
command=lambda: show_link_view(comp),
command=lambda: show_link_view(current_element(comp)),
)
if ox_page_view.is_ox_page(comp):
menu.add_command(
label="Page Editor",
command=lambda: show_ox_page_view(comp),
command=lambda: show_ox_page_view(current_element(comp)),
)
if user_service_view.is_user_service(comp):
menu.add_command(
label="User Manager",
command=lambda: show_user_service(comp),
command=lambda: show_user_service(current_element(comp)),
)
menu.add_separator()
if comp.tag == "comp":
# The app itself is named by its appName property, not by a component name.
menu.add_command(
label="Rename...",
command=lambda: open_rename_dialog(comp),
command=lambda: open_rename_dialog(current_element(comp)),
)
menu.add_command(
label="Delete Component",
command=lambda: delete_component(comp),
command=lambda: delete_component(current_element(comp)),
)
menu.add_separator()
menu.add_command(label="Link Mark", command=lambda: set_link_mark(comp))
menu.add_command(label="Link Mark", command=lambda: set_link_mark(current_element(comp)))
marked = app_state.link_mark_element
if marked is not None:
mark_name = marked.get("name", "?")
menu.add_command(
label=f'Link From "{mark_name}"',
command=lambda: open_link_dialog(marked, comp),
command=lambda: open_link_dialog(current_element(marked), current_element(comp)),
)
menu.add_command(
label=f'Link To "{mark_name}"',
command=lambda: open_link_dialog(comp, marked),
command=lambda: open_link_dialog(current_element(comp), current_element(marked)),
)