use super::{TreeNode, TreeState};
#[derive(Clone, Debug)]
pub(super) struct FlatNode {
pub(super) path: Vec<usize>,
pub(super) depth: usize,
pub(super) label: String,
pub(super) has_children: bool,
pub(super) is_expanded: bool,
}
impl<T: Clone> TreeState<T> {
pub(super) fn flatten(&self) -> Vec<FlatNode> {
let mut result = Vec::new();
if self.filter_text.is_empty() {
for (i, root) in self.roots.iter().enumerate() {
Self::flatten_node(root, vec![i], 0, &mut result);
}
} else {
let filter_lower = self.filter_text.to_lowercase();
for (i, root) in self.roots.iter().enumerate() {
Self::flatten_node_filtered(root, vec![i], 0, &filter_lower, &mut result);
}
}
result
}
fn flatten_node(
node: &TreeNode<T>,
path: Vec<usize>,
depth: usize,
result: &mut Vec<FlatNode>,
) {
result.push(FlatNode {
path: path.clone(),
depth,
label: node.label.clone(),
has_children: node.has_children(),
is_expanded: node.expanded,
});
if node.expanded {
for (i, child) in node.children.iter().enumerate() {
let mut child_path = path.clone();
child_path.push(i);
Self::flatten_node(child, child_path, depth + 1, result);
}
}
}
fn flatten_node_filtered(
node: &TreeNode<T>,
path: Vec<usize>,
depth: usize,
filter: &str,
result: &mut Vec<FlatNode>,
) {
let self_matches = node.label.to_lowercase().contains(filter);
let has_matching_descendant = node
.children
.iter()
.any(|child| Self::subtree_matches(child, filter));
if !self_matches && !has_matching_descendant {
return;
}
let show_expanded = if has_matching_descendant {
true
} else {
node.expanded
};
result.push(FlatNode {
path: path.clone(),
depth,
label: node.label.clone(),
has_children: node.has_children(),
is_expanded: show_expanded,
});
if show_expanded {
for (i, child) in node.children.iter().enumerate() {
let mut child_path = path.clone();
child_path.push(i);
Self::flatten_node_filtered(child, child_path, depth + 1, filter, result);
}
}
}
fn subtree_matches(node: &TreeNode<T>, filter: &str) -> bool {
if node.label.to_lowercase().contains(filter) {
return true;
}
node.children
.iter()
.any(|child| Self::subtree_matches(child, filter))
}
pub(super) fn get_node(&self, path: &[usize]) -> Option<&TreeNode<T>> {
if path.is_empty() {
return None;
}
let mut current = self.roots.get(path[0])?;
for &idx in &path[1..] {
current = current.children.get(idx)?;
}
Some(current)
}
pub(super) fn get_node_mut(&mut self, path: &[usize]) -> Option<&mut TreeNode<T>> {
if path.is_empty() {
return None;
}
let mut current = self.roots.get_mut(path[0])?;
for &idx in &path[1..] {
current = current.children.get_mut(idx)?;
}
Some(current)
}
pub(super) fn expand_all_recursive(node: &mut TreeNode<T>) {
if node.has_children() {
node.expand();
for child in &mut node.children {
Self::expand_all_recursive(child);
}
}
}
pub(super) fn collapse_all_recursive(node: &mut TreeNode<T>) {
node.collapse();
for child in &mut node.children {
Self::collapse_all_recursive(child);
}
}
pub(super) fn revalidate_selection(&mut self, prev_path: Option<Vec<usize>>) {
let flat = self.flatten();
if flat.is_empty() {
self.selected_index = None;
return;
}
if let Some(path) = prev_path {
if let Some(new_idx) = flat.iter().position(|n| n.path == path) {
self.selected_index = Some(new_idx);
return;
}
}
self.selected_index = Some(0);
}
}