Skip to main content

pacenotes_installer\tree/
selection.rs

1impl super::Tree {
2    /// A leaf's own checkbox, or a grouping row's derived from its leaves.
3    pub fn check_of(&self, index: usize) -> super::Check {
4        let node = &self.nodes[index];
5        if node.is_leaf() {
6            return if node.checked {
7                super::Check::Checked
8            } else {
9                super::Check::Unchecked
10            };
11        }
12        let leaves = self.leaves_under(Some(index));
13        let checked_count = leaves
14            .iter()
15            .filter(|&&leaf| self.nodes[leaf].checked)
16            .count();
17        match checked_count {
18            0 => super::Check::Unchecked,
19            count if count == leaves.len() => super::Check::Checked,
20            _ => super::Check::Partial,
21        }
22    }
23
24    /// Checks or unchecks `index` and everything under it; the cache is never touched.
25    pub fn set_checked(&mut self, index: usize, checked: bool) {
26        for leaf in self.leaves_under(Some(index)) {
27            self.nodes[leaf].checked = checked;
28        }
29    }
30
31    /// Unchecks the leaf for `key`, for a package scene 4b could not bring:
32    /// scene 5 must not offer what the install has no payload for.
33    pub fn uncheck_key(&mut self, key: &str) {
34        for leaf in self.leaves_under(None) {
35            if self.nodes[leaf].key.as_deref() == Some(key) {
36                self.nodes[leaf].checked = false;
37            }
38        }
39    }
40
41    pub fn checked_leaves(&self) -> Vec<usize> {
42        self.leaves_under(None)
43            .into_iter()
44            .filter(|&leaf| self.nodes[leaf].checked)
45            .collect()
46    }
47
48    /// The keys of every checked leaf, in display order.
49    pub fn checked_keys(&self) -> Vec<String> {
50        self.checked_leaves()
51            .into_iter()
52            .filter_map(|leaf| self.nodes[leaf].key.clone())
53            .collect()
54    }
55
56    /// The choice categories present in the tree with nothing checked under
57    /// them; an operator's new folder must not become a question.
58    pub fn categories_missing_a_pick(&self, choice_categories: &[&str]) -> Vec<String> {
59        self.roots
60            .iter()
61            .filter(|&&root| choice_categories.contains(&self.nodes[root].label.as_str()))
62            .filter(|&&root| self.check_of(root) == super::Check::Unchecked)
63            .map(|&root| self.nodes[root].label.clone())
64            .collect()
65    }
66
67    /// The choice categories with nothing to configure: no checked leaf whose
68    /// payload `is_cached` says is here. Every category the game's schema
69    /// asks about counts, present in this tree or not, since scene 5 cannot
70    /// make a pick from nothing.
71    pub fn categories_not_ready<'a>(
72        &self,
73        choice_categories: &[&'a str],
74        is_cached: &dyn Fn(&str) -> bool,
75    ) -> Vec<&'a str> {
76        let ready: Vec<&str> = self
77            .checked_leaves()
78            .into_iter()
79            .filter(|&leaf| self.nodes[leaf].key.as_deref().is_some_and(is_cached))
80            .map(|leaf| self.category_of(leaf))
81            .collect();
82        choice_categories
83            .iter()
84            .copied()
85            .filter(|category| !ready.contains(category))
86            .collect()
87    }
88
89    /// The checked leaves scene 6 fetches, updates included.
90    pub fn checked_needing_download(&self) -> Vec<String> {
91        self.checked_leaves()
92            .into_iter()
93            .filter(|&leaf| {
94                self.nodes[leaf]
95                    .state
96                    .is_some_and(super::LeafState::needs_download)
97            })
98            .filter_map(|leaf| self.nodes[leaf].key.clone())
99            .collect()
100    }
101}