use crate::traits::{DropPosition, OutlinerNode};
pub trait TreeOperations: OutlinerNode + Sized + Clone {
fn rename_node(&mut self, id: &Self::Id, new_name: String) -> bool {
if self.id() == *id {
return false;
}
for child in self.children_mut() {
if child.rename_node(id, new_name.clone()) {
return true;
}
}
false
}
fn remove_node(&mut self, id: &Self::Id) -> Option<Self> {
let children = self.children_mut();
for i in 0..children.len() {
if children[i].id() == *id {
return Some(children.remove(i));
}
}
for child in children.iter_mut() {
if let Some(node) = child.remove_node(id) {
return Some(node);
}
}
None
}
fn insert_node(&mut self, target_id: &Self::Id, node: Self, position: DropPosition) -> bool {
if self.id() == *target_id {
match position {
DropPosition::Inside => {
if self.is_collection() {
self.children_mut().push(node);
return true;
}
}
_ => {
return false;
}
}
}
let children = self.children_mut();
for i in 0..children.len() {
if children[i].id() == *target_id {
match position {
DropPosition::Before => {
children.insert(i, node);
return true;
}
DropPosition::After => {
children.insert(i + 1, node);
return true;
}
DropPosition::Inside => {
if children[i].is_collection() {
children[i].children_mut().push(node);
return true;
}
}
}
return false;
}
if children[i].insert_node(target_id, node.clone(), position) {
return true;
}
}
false
}
fn find_node(&self, id: &Self::Id) -> Option<&Self> {
if self.id() == *id {
return Some(self);
}
for child in self.children() {
if let Some(found) = child.find_node(id) {
return Some(found);
}
}
None
}
fn find_node_mut(&mut self, id: &Self::Id) -> Option<&mut Self> {
if self.id() == *id {
return Some(self);
}
for child in self.children_mut() {
if let Some(found) = child.find_node_mut(id) {
return Some(found);
}
}
None
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::traits::{ActionIcon, IconType};
#[derive(Clone, Debug, PartialEq)]
struct TestNode {
id: u64,
name: String,
is_collection: bool,
children: Vec<TestNode>,
}
impl TestNode {
fn new(id: u64, name: &str, is_collection: bool) -> Self {
Self {
id,
name: name.to_string(),
is_collection,
children: Vec::new(),
}
}
fn with_children(mut self, children: Vec<TestNode>) -> Self {
self.children = children;
self
}
}
impl OutlinerNode for TestNode {
type Id = u64;
fn id(&self) -> Self::Id {
self.id
}
fn name(&self) -> &str {
&self.name
}
fn is_collection(&self) -> bool {
self.is_collection
}
fn children(&self) -> &[Self] {
&self.children
}
fn children_mut(&mut self) -> &mut Vec<Self> {
&mut self.children
}
fn icon(&self) -> Option<IconType> {
if self.is_collection {
Some(IconType::Collection)
} else {
Some(IconType::Entity)
}
}
fn action_icons(&self) -> Vec<ActionIcon> {
vec![]
}
}
impl TreeOperations for TestNode {}
#[test]
fn test_remove_node_direct_child() {
let mut root = TestNode::new(1, "root", true).with_children(vec![
TestNode::new(2, "child1", false),
TestNode::new(3, "child2", false),
]);
let removed = root.remove_node(&2);
assert!(removed.is_some());
assert_eq!(removed.unwrap().id, 2);
assert_eq!(root.children.len(), 1);
assert_eq!(root.children[0].id, 3);
}
#[test]
fn test_remove_node_nested() {
let mut root = TestNode::new(1, "root", true).with_children(vec![
TestNode::new(2, "child1", true).with_children(vec![
TestNode::new(3, "grandchild", false),
]),
]);
let removed = root.remove_node(&3);
assert!(removed.is_some());
assert_eq!(removed.unwrap().id, 3);
assert_eq!(root.children[0].children.len(), 0);
}
#[test]
fn test_remove_node_not_found() {
let mut root = TestNode::new(1, "root", true).with_children(vec![
TestNode::new(2, "child1", false),
]);
let removed = root.remove_node(&999);
assert!(removed.is_none());
}
#[test]
fn test_insert_node_inside_collection() {
let mut root = TestNode::new(1, "root", true);
let new_node = TestNode::new(2, "new", false);
let result = root.insert_node(&1, new_node, DropPosition::Inside);
assert!(result);
assert_eq!(root.children.len(), 1);
assert_eq!(root.children[0].id, 2);
}
#[test]
fn test_insert_node_before() {
let mut root = TestNode::new(1, "root", true).with_children(vec![
TestNode::new(2, "child1", false),
TestNode::new(3, "child2", false),
]);
let new_node = TestNode::new(4, "new", false);
let result = root.insert_node(&3, new_node, DropPosition::Before);
assert!(result);
assert_eq!(root.children.len(), 3);
assert_eq!(root.children[1].id, 4);
assert_eq!(root.children[2].id, 3);
}
#[test]
fn test_insert_node_after() {
let mut root = TestNode::new(1, "root", true).with_children(vec![
TestNode::new(2, "child1", false),
TestNode::new(3, "child2", false),
]);
let new_node = TestNode::new(4, "new", false);
let result = root.insert_node(&2, new_node, DropPosition::After);
assert!(result);
assert_eq!(root.children.len(), 3);
assert_eq!(root.children[0].id, 2);
assert_eq!(root.children[1].id, 4);
}
#[test]
fn test_insert_node_inside_non_collection() {
let mut root = TestNode::new(1, "root", true).with_children(vec![
TestNode::new(2, "child1", false),
]);
let new_node = TestNode::new(3, "new", false);
let result = root.insert_node(&2, new_node, DropPosition::Inside);
assert!(!result);
assert_eq!(root.children.len(), 1);
}
#[test]
fn test_find_node() {
let root = TestNode::new(1, "root", true).with_children(vec![
TestNode::new(2, "child1", true).with_children(vec![
TestNode::new(3, "grandchild", false),
]),
]);
let found = root.find_node(&3);
assert!(found.is_some());
assert_eq!(found.unwrap().id, 3);
let not_found = root.find_node(&999);
assert!(not_found.is_none());
}
#[test]
fn test_find_node_mut() {
let mut root = TestNode::new(1, "root", true).with_children(vec![
TestNode::new(2, "child1", false),
]);
let found = root.find_node_mut(&2);
assert!(found.is_some());
if let Some(node) = found {
node.name = "modified".to_string();
}
assert_eq!(root.children[0].name, "modified");
}
}