diff --git a/src/app/update/command.rs b/src/app/update/command.rs index 12499be5e..d9aa9abda 100644 --- a/src/app/update/command.rs +++ b/src/app/update/command.rs @@ -1103,7 +1103,8 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task { .get(idx) .map(|l| l.name.clone()) .unwrap_or_default(); - let case_only_rename = new_name.eq_ignore_ascii_case(&old_name); + let old_key = old_name.to_uppercase(); + let case_only_rename = new_name.to_uppercase() == old_key; if !new_name.is_empty() && new_name != old_name && (case_only_rename @@ -1121,19 +1122,30 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task { if !nl.handle.is_valid() { nl.handle = self.tabs[i].scene.document.allocate_handle(); } + let layer_handle = nl.handle; let _ = self.tabs[i].scene.document.layers.add(nl); for e in self.tabs[i].scene.document.entities_mut() { - if e.as_entity().layer() == old_name { + if e.as_entity().layer().to_uppercase() == old_key { e.as_entity_mut().set_layer(new_name.clone()); } } - if self.tabs[i] - .active_layer - .eq_ignore_ascii_case(&old_name) - { + self.tabs[i].scene.invalidate_dependency_index(); + + if self.tabs[i].active_layer.to_uppercase() == old_key { self.tabs[i].active_layer = new_name.clone(); + } + if self.tabs[i] + .scene + .document + .header + .current_layer_name + .to_uppercase() + == old_key + { self.tabs[i].scene.document.header.current_layer_name = new_name.clone(); + self.tabs[i].scene.document.header.current_layer_handle = + layer_handle; } self.tabs[i].dirty = true; } @@ -2617,6 +2629,8 @@ fn block_attr_prompts( #[cfg(test)] mod layer_rename_tests { use crate::app::OpenCADStudio; + use acadrust::entities::Line; + use acadrust::{EntityType, Handle}; fn app_with_editing_layer() -> OpenCADStudio { let mut app = OpenCADStudio::new_for_test(); @@ -2625,52 +2639,143 @@ mod layer_rename_tests { app } - #[test] - fn current_layer_rename_updates_active_layer() { - let mut app = app_with_editing_layer(); + fn rename_layer(app: &mut OpenCADStudio, old_name: &str, new_name: &str) { let i = app.active_tab; - let idx = app.tabs[i] - .layers - .editing - .expect("new layer is being edited"); - app.tabs[i].layers.selected = Some(idx); - let _ = app.on_layer_set_current(); - - app.tabs[i].layers.editing = Some(idx); - app.tabs[i].layers.edit_buf = "Renamed".to_string(); - let _ = app.on_layer_rename_commit(); - - assert_eq!(app.tabs[i].active_layer, "Renamed"); - assert_eq!( - app.tabs[i].scene.document.header.current_layer_name, - "Renamed" - ); - assert_eq!(app.tabs[i].layers.current_layer, "Renamed"); - assert_eq!(app.ribbon.active_layer, "Renamed"); - } - - #[test] - fn layer_rename_allows_case_only_change() { - let mut app = app_with_editing_layer(); - let i = app.active_tab; - assert!(app.tabs[i].layers.editing.is_some()); - app.tabs[i].layers.edit_buf = "TEST".to_string(); - let _ = app.on_layer_rename_commit(); - let idx = app.tabs[i] .layers .layers .iter() - .position(|layer| layer.name == "TEST") - .expect("first rename succeeded"); + .position(|layer| layer.name == old_name) + .expect("layer exists in panel"); app.tabs[i].layers.editing = Some(idx); - app.tabs[i].layers.edit_buf = "test".to_string(); + app.tabs[i].layers.edit_buf = new_name.to_string(); let _ = app.on_layer_rename_commit(); + } + + #[test] + fn layer_rename_allows_ascii_case_only_change() { + let mut app = app_with_editing_layer(); + let i = app.active_tab; + let old_name = app.tabs[i].layers.edit_buf.clone(); + rename_layer(&mut app, &old_name, "TEST"); + let handle = app.tabs[i].scene.document.layers.get("TEST").unwrap().handle; + + rename_layer(&mut app, "TEST", "test"); + + let layer = app.tabs[i].scene.document.layers.get("test").unwrap(); + assert_eq!(layer.name, "test"); + assert_eq!(layer.handle, handle); + } + + #[test] + fn layer_rename_allows_unicode_case_only_change() { + let mut app = app_with_editing_layer(); + let i = app.active_tab; + let old_name = app.tabs[i].layers.edit_buf.clone(); + rename_layer(&mut app, &old_name, "é"); + + rename_layer(&mut app, "é", "É"); - assert!(app.tabs[i].scene.document.layers.get("test").is_some()); assert_eq!( - app.tabs[i].scene.document.layers.get("test").unwrap().name, - "test" + app.tabs[i].scene.document.layers.get("É").unwrap().name, + "É" ); } + + #[test] + fn current_layer_rename_updates_name_and_allocated_handle() { + let mut app = app_with_editing_layer(); + let i = app.active_tab; + let idx = app.tabs[i].layers.editing.expect("new layer is being edited"); + let old_name = app.tabs[i].layers.layers[idx].name.clone(); + app.tabs[i] + .scene + .document + .layers + .get_mut(&old_name) + .unwrap() + .handle = Handle::NULL; + app.tabs[i].layers.selected = Some(idx); + let _ = app.on_layer_set_current(); + + rename_layer(&mut app, &old_name, "Renamed"); + + let layer = app.tabs[i] + .scene + .document + .layers + .get("Renamed") + .unwrap(); + assert!(layer.handle.is_valid()); + assert_eq!(app.tabs[i].active_layer, "Renamed"); + assert_eq!(app.tabs[i].layers.current_layer, "Renamed"); + assert_eq!(app.ribbon.active_layer, "Renamed"); + assert_eq!( + app.tabs[i].scene.document.header.current_layer_name, + "Renamed" + ); + assert_eq!( + app.tabs[i].scene.document.header.current_layer_handle, + layer.handle + ); + } + + #[test] + fn layer_rename_keeps_independent_current_layer_mirrors() { + let mut app = app_with_editing_layer(); + let i = app.active_tab; + let old_name = app.tabs[i].layers.edit_buf.clone(); + rename_layer(&mut app, &old_name, "A"); + let _ = app.on_layer_new(); + let b_idx = app.tabs[i].layers.editing.expect("new layer is being edited"); + app.tabs[i].layers.selected = Some(b_idx); + let _ = app.on_layer_set_current(); + let header_name = app.tabs[i].scene.document.header.current_layer_name.clone(); + let header_handle = app.tabs[i].scene.document.header.current_layer_handle; + app.tabs[i].active_layer = "A".to_string(); + + rename_layer(&mut app, "A", "Renamed"); + + assert_eq!(app.tabs[i].active_layer, "Renamed"); + assert_eq!( + app.tabs[i].scene.document.header.current_layer_name, + header_name + ); + assert_eq!( + app.tabs[i].scene.document.header.current_layer_handle, + header_handle + ); + } + + #[test] + fn layer_rename_updates_mixed_case_entity_references() { + let mut app = app_with_editing_layer(); + let i = app.active_tab; + let old_name = app.tabs[i].layers.edit_buf.clone(); + rename_layer(&mut app, &old_name, "TEST"); + let mut line = Line::new(); + line.common.layer = "test".to_string(); + let handle = app.tabs[i].scene.add_entity(EntityType::Line(line)); + app.tabs[i] + .scene + .invalidate_layer_dependencies(&["TEST".to_string()]); + + rename_layer(&mut app, "TEST", "Renamed"); + + assert_eq!( + app.tabs[i] + .scene + .document + .get_entity(handle) + .unwrap() + .common() + .layer, + "Renamed" + ); + let epoch = app.tabs[i].scene.geometry_epoch; + app.tabs[i] + .scene + .invalidate_layer_dependencies(&["Renamed".to_string()]); + assert_ne!(app.tabs[i].scene.geometry_epoch, epoch); + } }