Add Rename to the component right-click menu
Rename is offered from both the canvas and the navigation tree. Names are checked against Sedona's Component.checkName rules (1-7 ASCII chars, a letter first, then letters, digits or '_') and must be unique among siblings. In file mode link paths through the old name are rewritten and the rename is one undo step; in live mode it goes to the device via Sox and warns if the device rejects it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1387,6 +1387,71 @@ def open_link_dialog(source_element, target_element):
|
||||
ttk.Button(btn_frame, text="Cancel", width=10, command=dialog.destroy).pack(side=tk.LEFT, padx=5)
|
||||
|
||||
|
||||
def open_rename_dialog(comp):
|
||||
"""Asks for a new name, checking Sedona's naming rules as it is typed."""
|
||||
window = app_state.window
|
||||
root = app_state.xml_root_element
|
||||
if root is None or comp.tag != "comp":
|
||||
return
|
||||
parent = find_parent_element(root, comp)
|
||||
old_name = comp.get("name", "")
|
||||
|
||||
dialog = tk.Toplevel(window)
|
||||
dialog.title("Rename Component")
|
||||
dialog.resizable(False, False)
|
||||
dialog.transient(window)
|
||||
dialog.grab_set()
|
||||
dialog.geometry(f"+{window.winfo_x() + 100}+{window.winfo_y() + 60}")
|
||||
|
||||
main_frame = tk.Frame(dialog, padx=10, pady=10)
|
||||
main_frame.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
tk.Label(main_frame, text=f"New name for '{old_name}' [id: {comp.get('id', '?')}]:",
|
||||
anchor="w").grid(row=0, column=0, sticky="w")
|
||||
name_var = tk.StringVar(value=old_name)
|
||||
entry = ttk.Entry(main_frame, textvariable=name_var, width=24)
|
||||
entry.grid(row=1, column=0, sticky="we", pady=(4, 0))
|
||||
tk.Label(main_frame, text="1-7 characters: a letter, then letters, digits or '_'.",
|
||||
anchor="w", fg="#666666").grid(row=2, column=0, sticky="w", pady=(4, 0))
|
||||
error_var = tk.StringVar(value="")
|
||||
tk.Label(main_frame, textvariable=error_var, anchor="w", fg="#b00020",
|
||||
wraplength=320, justify="left").grid(row=3, column=0, sticky="w")
|
||||
|
||||
btn_frame = tk.Frame(main_frame)
|
||||
btn_frame.grid(row=4, column=0, pady=(10, 0))
|
||||
ok_button = ttk.Button(btn_frame, text="OK", width=10)
|
||||
ok_button.pack(side=tk.LEFT, padx=5)
|
||||
ttk.Button(btn_frame, text="Cancel", width=10,
|
||||
command=dialog.destroy).pack(side=tk.LEFT, padx=5)
|
||||
|
||||
def current_error():
|
||||
name = name_var.get()
|
||||
if name == old_name:
|
||||
return None
|
||||
return sax_file.check_component_name(name, parent, comp)
|
||||
|
||||
def on_change(*_):
|
||||
err = current_error()
|
||||
error_var.set(err or "")
|
||||
ok_button.state(["disabled"] if err else ["!disabled"])
|
||||
|
||||
def on_ok(*_):
|
||||
if current_error() is not None:
|
||||
return
|
||||
new_name = name_var.get()
|
||||
dialog.destroy()
|
||||
# An open panel may show the old name, so it is refreshed along with the sheet.
|
||||
if new_name != old_name and sax_file.rename_component(comp, new_name):
|
||||
refresh_all_views()
|
||||
|
||||
ok_button.configure(command=on_ok)
|
||||
name_var.trace_add("write", on_change)
|
||||
entry.bind("<Return>", on_ok)
|
||||
dialog.bind("<Escape>", lambda _: dialog.destroy())
|
||||
entry.focus_set()
|
||||
entry.select_range(0, tk.END)
|
||||
|
||||
|
||||
def fill_component_popup(menu, comp):
|
||||
"""Fills a popup with the actions that apply to one component.
|
||||
|
||||
@@ -1415,6 +1480,12 @@ def fill_component_popup(menu, comp):
|
||||
command=lambda: show_user_service(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),
|
||||
)
|
||||
menu.add_command(
|
||||
label="Delete Component",
|
||||
command=lambda: delete_component(comp),
|
||||
|
||||
Reference in New Issue
Block a user