use super::Node;
#[derive(Default, Clone)]
pub struct TreeState {
open: Vec<String>,
selected: Option<String>,
}
impl TreeState {
pub fn is_open<V>(&self, node: &Node<V>) -> bool {
self.open.contains(node.id())
}
pub fn is_closed<V>(&self, node: &Node<V>) -> bool {
!self.is_open(node)
}
pub fn selected(&self) -> Option<&str> {
self.selected.as_deref()
}
pub fn is_selected<V>(&self, node: &Node<V>) -> bool {
self.selected
.as_ref()
.map(|x| x == node.id())
.unwrap_or(false)
}
pub fn first_sibling<'a, V>(&self, tree: &'a Node<V>) -> Option<&'a Node<V>> {
let selected = self.selected.as_ref()?;
let parent = tree.parent(selected)?;
parent.iter().next()
}
pub fn last_sibling<'a, V>(&self, tree: &'a Node<V>) -> Option<&'a Node<V>> {
let selected = self.selected.as_ref()?;
let parent = tree.parent(selected)?;
parent.iter().last()
}
pub fn tree_changed<V>(&mut self, root: &Node<V>, preserve: bool) {
if preserve {
self.selected = self
.selected
.take()
.map(|selected| root.query(&selected).unwrap_or(root).id().to_string());
self.open.retain(|x| root.query(x).is_some());
} else {
self.open = Vec::new();
self.selected = Some(root.id().to_string());
}
}
pub fn open<V>(&mut self, root: &Node<V>) {
if let Some(selected) = self.selected.as_ref()
&& let Some(node) = root.query(selected)
{
self.open_node(root, node);
}
}
pub fn close<V>(&mut self, root: &Node<V>) {
if let Some(selected) = self.selected.as_ref()
&& let Some(node) = root.query(selected)
&& self.is_open(node)
{
self.close_node(node);
}
}
pub fn move_down<V>(&mut self, root: &Node<V>) {
if let Some(selected) = self.selected.take() {
if let Some(node) = root.query(&selected) {
if !node.is_leaf() && self.is_open(node) {
self.selected = Some(node.iter().next().unwrap().id().to_string());
} else {
if let Some(sibling) = self.next_sibling(root, node) {
self.selected = Some(sibling.id().to_string());
} else {
let mut current = &selected;
loop {
if let Some(parent) = root.parent(current) {
current = parent.id();
if let Some(sibling) = self.next_sibling(root, parent) {
self.selected = Some(sibling.id().to_string());
break;
}
} else {
self.selected = Some(selected);
break;
}
}
}
}
}
}
}
pub fn move_up<V>(&mut self, root: &Node<V>) {
if let Some(selected) = self.selected.take() {
if let Some(parent) = root.parent(&selected) {
self.selected = Some(
self.previous_sibling(root, root.query(&selected).unwrap())
.map(|x| self.get_last_open_heir(x))
.unwrap_or(parent)
.id()
.to_string(),
);
} else {
self.selected = Some(selected);
}
}
}
pub fn select<V>(&mut self, root: &Node<V>, node: &Node<V>) {
self.open_ancestors(root, node);
self.selected = Some(node.id().to_string());
}
fn close_node<V>(&mut self, node: &Node<V>) {
self.open.retain(|x| x != node.id());
self.close_children(node);
}
fn open_node<V>(&mut self, root: &Node<V>, node: &Node<V>) {
if !node.is_leaf() && self.is_closed(node) {
self.open.push(node.id().to_string());
}
self.open_ancestors(root, node);
}
fn close_children<V>(&mut self, node: &Node<V>) {
node.iter().for_each(|x| self.close_node(x));
}
fn open_ancestors<V>(&mut self, root: &Node<V>, node: &Node<V>) {
if let Some(parent) = root.parent(node.id()) {
self.open_node(root, parent);
}
}
fn previous_sibling<'a, V>(
&mut self,
root: &'a Node<V>,
node: &'a Node<V>,
) -> Option<&'a Node<V>> {
let parent = root.parent(node.id())?;
let mut prev_node = None;
for child in parent.iter() {
if child.id() == node.id() {
break;
}
prev_node = Some(child);
}
prev_node
}
fn next_sibling<'a, V>(&mut self, root: &'a Node<V>, node: &'a Node<V>) -> Option<&'a Node<V>> {
let parent = root.parent(node.id())?;
let mut keep_next = false;
for child in parent.iter() {
if keep_next {
return Some(child);
} else if child.id() == node.id() {
keep_next = true;
}
}
None
}
fn get_last_open_heir<'a, V>(&self, node: &'a Node<V>) -> &'a Node<V> {
if self.is_open(node) {
if let Some(child) = node.iter().last() {
self.get_last_open_heir(child)
} else {
node
}
} else {
node
}
}
#[cfg(test)]
pub fn force_open(&mut self, open: &[&str]) {
self.open = open.iter().map(|x| x.to_string()).collect();
}
}
#[cfg(test)]
mod test {
use pretty_assertions::assert_eq;
use super::*;
use crate::mock::mock_tree;
#[test]
fn should_initialize_tree_state() {
let state = TreeState::default();
assert!(state.open.is_empty());
assert!(state.selected().is_none());
}
#[test]
fn should_select_nodes() {
let mut state = TreeState::default();
let tree = mock_tree();
state.select(tree.root(), tree.root().query(&String::from("bA")).unwrap());
assert_eq!(state.selected().unwrap(), "bA");
assert_eq!(state.open.len(), 2);
assert!(state.is_open(tree.root().query(&String::from("b")).unwrap()));
assert!(state.is_open(tree.root()));
}
#[test]
fn should_open_and_close_nodes() {
let mut state = TreeState::default();
let tree = mock_tree();
let ba = tree.root().query(&String::from("bA")).unwrap();
state.select(tree.root(), ba);
state.open(tree.root());
assert!(state.is_open(ba));
assert!(state.is_open(tree.root().query(&String::from("b")).unwrap()));
assert!(state.is_open(tree.root()));
assert_eq!(state.open.len(), 3);
let ba0 = tree.root().query(&String::from("bA0")).unwrap();
state.select(tree.root(), ba0);
state.open(tree.root());
assert!(state.is_open(ba0));
assert_eq!(state.open.len(), 4);
let b = tree.root().query(&String::from("b")).unwrap();
state.select(tree.root(), b);
state.close(tree.root());
assert!(state.is_closed(b));
assert!(state.is_closed(ba));
assert!(state.is_closed(ba0));
assert!(state.is_open(tree.root()));
}
#[test]
fn should_not_open_twice() {
let mut state = TreeState::default();
let tree = mock_tree();
state.select(tree.root(), tree.root());
state.open(tree.root());
assert_eq!(state.open.len(), 1);
assert!(state.is_open(tree.root()));
state.open(tree.root());
assert_eq!(state.open.len(), 1);
assert!(state.is_open(tree.root()));
}
#[test]
fn should_find_previous_sibling() {
let mut state = TreeState::default();
let tree = mock_tree();
let bb4 = tree.root().query(&String::from("bB4")).unwrap();
let bb3 = tree.root().query(&String::from("bB3")).unwrap();
assert_eq!(state.previous_sibling(tree.root(), bb4).unwrap(), bb3);
let bb0 = tree.root().query(&String::from("bB0")).unwrap();
assert!(state.previous_sibling(tree.root(), bb0).is_none());
}
#[test]
fn should_find_next_sibling() {
let mut state = TreeState::default();
let tree = mock_tree();
let bb4 = tree.root().query(&String::from("bB4")).unwrap();
let bb5 = tree.root().query(&String::from("bB5")).unwrap();
assert_eq!(state.next_sibling(tree.root(), bb4).unwrap(), bb5);
assert!(state.next_sibling(tree.root(), bb5).is_none());
}
#[test]
fn should_find_first_sibling() {
let mut state = TreeState::default();
let tree = mock_tree();
let bb4 = tree.root().query(&String::from("bB4")).unwrap();
state.select(tree.root(), bb4);
let bb0 = tree.root().query(&String::from("bB0")).unwrap();
assert_eq!(state.first_sibling(tree.root()).unwrap(), bb0);
state.select(tree.root(), tree.root());
assert!(state.first_sibling(tree.root()).is_none());
}
#[test]
fn should_find_last_sibling() {
let mut state = TreeState::default();
let tree = mock_tree();
let bb2 = tree.root().query(&String::from("bB2")).unwrap();
state.select(tree.root(), bb2);
let bb5 = tree.root().query(&String::from("bB5")).unwrap();
assert_eq!(state.last_sibling(tree.root()).unwrap(), bb5);
state.select(tree.root(), tree.root());
assert!(state.last_sibling(tree.root()).is_none());
}
#[test]
fn should_preserve_tree_state() {
let mut state = TreeState::default();
let tree = mock_tree();
let ca = tree.root().query(&String::from("cA")).unwrap();
state.select(tree.root(), ca);
state.open(tree.root());
let bb5 = tree.root().query(&String::from("bB5")).unwrap();
state.select(tree.root(), bb5);
state.tree_changed(tree.root(), true);
assert_eq!(state.open.len(), 5);
assert!(state.is_open(ca));
assert_eq!(state.selected().unwrap(), "bB5");
}
#[test]
fn should_not_preserve_tree_state() {
let mut state = TreeState::default();
let mut tree = mock_tree();
let ca = tree.root().query(&String::from("cA")).unwrap();
state.select(tree.root(), ca);
state.open(tree.root());
let bb5 = tree.root().query(&String::from("bB5")).unwrap();
state.select(tree.root(), bb5);
tree.root_mut()
.query_mut(&String::from("b"))
.unwrap()
.remove_child(&String::from("bB"));
tree.root_mut().remove_child(&String::from("c"));
state.tree_changed(tree.root(), true);
assert_eq!(state.selected().unwrap(), "/");
assert_eq!(state.open.len(), 2);
assert_eq!(state.open, vec![String::from("/"), String::from("b")]);
assert!(state.is_open(tree.root()));
}
#[test]
fn should_reinitialize_tree_state() {
let mut state = TreeState::default();
let tree = mock_tree();
let ca = tree.root().query(&String::from("cA")).unwrap();
state.select(tree.root(), ca);
state.open(tree.root());
let bb5 = tree.root().query(&String::from("bB5")).unwrap();
state.select(tree.root(), bb5);
state.tree_changed(tree.root(), false);
assert!(state.open.is_empty());
assert_eq!(state.selected().unwrap(), "/");
}
#[test]
fn should_move_cursor_down_on_sibling() {
let mut state = TreeState::default();
let tree = mock_tree();
let bb3 = tree.root().query(&String::from("bB3")).unwrap();
state.select(tree.root(), bb3);
state.move_down(tree.root());
assert_eq!(state.selected().unwrap(), "bB4");
state.move_down(tree.root());
assert_eq!(state.selected().unwrap(), "bB5");
}
#[test]
fn should_move_cursor_down_to_next_lower_node_if_last_child() {
let mut state = TreeState::default();
let tree = mock_tree();
let bb5 = tree.root().query(&String::from("bB5")).unwrap();
state.select(tree.root(), bb5);
state.move_down(tree.root());
assert_eq!(state.selected().unwrap(), "c");
}
#[test]
fn should_move_cursor_down_to_child_if_parent_is_open() {
let mut state = TreeState::default();
let tree = mock_tree();
let b = tree.root().query(&String::from("b")).unwrap();
state.select(tree.root(), b);
state.open(tree.root());
state.move_down(tree.root());
assert_eq!(state.selected().unwrap(), "bA");
state.open(tree.root());
state.move_down(tree.root());
assert_eq!(state.selected().unwrap(), "bA0");
}
#[test]
fn should_move_cursor_down_to_next_sibling_if_node_is_closed() {
let mut state = TreeState::default();
let tree = mock_tree();
let aa = tree.root().query(&String::from("aA")).unwrap();
state.select(tree.root(), aa);
state.move_down(tree.root());
assert_eq!(state.selected().unwrap(), "aB");
state.move_down(tree.root());
assert_eq!(state.selected().unwrap(), "aC");
}
#[test]
fn should_not_move_cursor_down_if_root_is_closed() {
let mut state = TreeState::default();
let tree = mock_tree();
state.select(tree.root(), tree.root());
state.move_down(tree.root());
assert_eq!(state.selected().unwrap(), "/");
}
#[test]
fn should_not_move_cursor_down_if_last_element_is_selected() {
let mut state = TreeState::default();
let tree = mock_tree();
let ca2 = tree.root().query(&String::from("cA2")).unwrap();
state.select(tree.root(), ca2);
state.move_down(tree.root());
assert_eq!(state.selected().unwrap(), "cA2");
}
#[test]
fn should_move_cursor_up_on_sibling() {
let mut state = TreeState::default();
let tree = mock_tree();
let bb4 = tree.root().query(&String::from("bB4")).unwrap();
state.select(tree.root(), bb4);
state.move_up(tree.root());
assert_eq!(state.selected().unwrap(), "bB3");
state.move_up(tree.root());
assert_eq!(state.selected().unwrap(), "bB2");
}
#[test]
fn should_move_cursor_up_on_deepest_child_of_previous_sibling() {
let mut state = TreeState::default();
let tree = mock_tree();
state.select(tree.root(), tree.root().query(&String::from("bB")).unwrap());
state.open(tree.root());
state.select(tree.root(), tree.root().query(&String::from("c")).unwrap());
state.move_up(tree.root());
assert_eq!(state.selected().unwrap(), "bB5");
}
#[test]
fn should_move_cursor_up_to_parent_if_first_child() {
let mut state = TreeState::default();
let tree = mock_tree();
state.select(
tree.root(),
tree.root().query(&String::from("bB0")).unwrap(),
);
state.move_up(tree.root());
assert_eq!(state.selected().unwrap(), "bB");
state.move_up(tree.root());
assert_eq!(state.selected().unwrap(), "bA");
state.move_up(tree.root());
assert_eq!(state.selected().unwrap(), "b");
}
#[test]
fn should_not_move_cursor_up_if_root_is_selected() {
let mut state = TreeState::default();
let tree = mock_tree();
state.select(tree.root(), tree.root());
state.move_up(tree.root());
assert_eq!(state.selected().unwrap(), "/");
}
#[test]
fn should_get_last_open_heir() {
let mut state = TreeState::default();
let tree = mock_tree();
state.select(tree.root(), tree.root().query(&String::from("aA")).unwrap());
state.open(tree.root());
state.select(tree.root(), tree.root().query(&String::from("aB")).unwrap());
state.open(tree.root());
state.select(tree.root(), tree.root().query(&String::from("aC")).unwrap());
state.open(tree.root());
state.select(tree.root(), tree.root().query(&String::from("bB")).unwrap());
state.open(tree.root());
assert_eq!(
state
.get_last_open_heir(tree.root().query(&String::from("bB")).unwrap())
.id()
.as_str(),
"bB5"
);
assert_eq!(
state
.get_last_open_heir(tree.root().query(&String::from("a")).unwrap())
.id()
.as_str(),
"aC0"
);
}
#[test]
fn get_last_open_heir_0_children() {
let mut state = TreeState::default();
let mut tree = mock_tree();
state.select(tree.root(), tree.root());
state.open(tree.root());
let node = &tree.root().children()[0];
let node_id = node.id().to_string();
state.select(tree.root(), node);
state.open(tree.root());
tree.root_mut().query_mut(&node_id).unwrap().clear();
state.get_last_open_heir(&tree.root().children()[0]);
}
}